Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2016-06-27 12:04:12 +02:00
commit fa3eb6a9b1
239 changed files with 19114 additions and 4962 deletions

View File

@ -136,9 +136,9 @@
</hbox>
</vbox>
<vbox>
<description>&doNotTrack.pre.label;<html:a
class="inline-link" id="doNotTrackSettings" href="#"
>&doNotTrack.settings.label;</html:a>&doNotTrack.post.label;</description>
<description>&doNotTrack.pre.label;<label
class="text-link" id="doNotTrackSettings" href="#"
>&doNotTrack.settings.label;</label>&doNotTrack.post.label;</description>
</vbox>
</groupbox>
@ -165,11 +165,11 @@
<vbox flex="1">
<description>&rememberDescription.label;</description>
<separator class="thin"/>
<description>&rememberActions.pre.label;<html:a
class="inline-link" id="historyRememberClear" href="#"
>&rememberActions.clearHistory.label;</html:a>&rememberActions.middle.label;<html:a
class="inline-link" id="historyRememberCookies" href="#"
>&rememberActions.removeCookies.label;</html:a>&rememberActions.post.label;</description>
<description>&rememberActions.pre.label;<label
class="text-link" id="historyRememberClear" href="#"
>&rememberActions.clearHistory.label;</label>&rememberActions.middle.label;<label
class="text-link" id="historyRememberCookies" href="#"
>&rememberActions.removeCookies.label;</label>&rememberActions.post.label;</description>
</vbox>
</hbox>
</vbox>
@ -178,9 +178,9 @@
<vbox flex="1">
<description>&dontrememberDescription.label;</description>
<separator class="thin"/>
<description>&dontrememberActions.pre.label;<html:a
class="inline-link" id="historyDontRememberClear" href="#"
>&dontrememberActions.clearHistory.label;</html:a>&dontrememberActions.post.label;</description>
<description>&dontrememberActions.pre.label;<label
class="text-link" id="historyDontRememberClear" href="#"
>&dontrememberActions.clearHistory.label;</label>&dontrememberActions.post.label;</description>
</vbox>
</hbox>
</vbox>

View File

@ -36,6 +36,31 @@ DocumentTimeline::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return DocumentTimelineBinding::Wrap(aCx, this, aGivenProto);
}
/* static */ already_AddRefed<DocumentTimeline>
DocumentTimeline::Constructor(const GlobalObject& aGlobal,
const DOMHighResTimeStamp& aOriginTime,
ErrorResult& aRv)
{
nsIDocument* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
if (!doc) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
TimeDuration originTime = TimeDuration::FromMilliseconds(aOriginTime);
if (originTime == TimeDuration::Forever() ||
originTime == -TimeDuration::Forever()) {
nsAutoString inputOriginTime;
inputOriginTime.AppendFloat(aOriginTime);
aRv.ThrowTypeError<dom::MSG_TIME_VALUE_OUT_OF_RANGE>(
NS_LITERAL_STRING("Origin time"));
return nullptr;
}
RefPtr<DocumentTimeline> timeline = new DocumentTimeline(doc, originTime);
return timeline.forget();
}
Nullable<TimeDuration>
DocumentTimeline::GetCurrentTime() const
{
@ -88,7 +113,9 @@ DocumentTimeline::ToTimelineTime(const TimeStamp& aTimeStamp) const
return result;
}
result.SetValue(aTimeStamp - timing->GetNavigationStartTimeStamp());
result.SetValue(aTimeStamp
- timing->GetNavigationStartTimeStamp()
- mOriginTime);
return result;
}
@ -204,7 +231,7 @@ DocumentTimeline::ToTimeStamp(const TimeDuration& aTimeDuration) const
return result;
}
result = timing->GetNavigationStartTimeStamp() + aTimeDuration;
result = timing->GetNavigationStartTimeStamp() + aTimeDuration + mOriginTime;
return result;
}

View File

@ -10,6 +10,7 @@
#include "mozilla/TimeStamp.h"
#include "AnimationTimeline.h"
#include "nsIDocument.h"
#include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp
#include "nsRefreshDriver.h"
struct JSContext;
@ -28,10 +29,11 @@ class DocumentTimeline final
, public nsARefreshObserver
{
public:
explicit DocumentTimeline(nsIDocument* aDocument)
DocumentTimeline(nsIDocument* aDocument, const TimeDuration& aOriginTime)
: AnimationTimeline(aDocument->GetParentObject())
, mDocument(aDocument)
, mIsObservingRefreshDriver(false)
, mOriginTime(aOriginTime)
{
}
@ -50,6 +52,11 @@ public:
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<DocumentTimeline>
Constructor(const GlobalObject& aGlobal,
const DOMHighResTimeStamp& aOriginTime,
ErrorResult& aRv);
// AnimationTimeline methods
virtual Nullable<TimeDuration> GetCurrentTime() const override;
@ -84,6 +91,8 @@ protected:
// iframe).
mutable TimeStamp mLastRefreshDriverTime;
bool mIsObservingRefreshDriver;
TimeDuration mOriginTime;
};
} // namespace dom

View File

@ -37,6 +37,7 @@ support-files =
document-timeline/file_document-timeline.html
mozilla/file_deferred_start.html
mozilla/file_disabled_properties.html
mozilla/file_document-timeline-origin-time-range.html
mozilla/file_hide_and_show.html
mozilla/file_partial_keyframes.html
style/file_animation-seeking-with-current-time.html
@ -82,6 +83,7 @@ skip-if = buildapp == 'mulet'
[mozilla/test_deferred_start.html]
skip-if = (toolkit == 'gonk' && debug)
[mozilla/test_disabled_properties.html]
[mozilla/test_document-timeline-origin-time-range.html]
[mozilla/test_hide_and_show.html]
[mozilla/test_partial_keyframes.html]
[style/test_animation-seeking-with-current-time.html]

View File

@ -0,0 +1,26 @@
<!doctype html>
<meta charset=utf-8>
<script src="../testcommon.js"></script>
<body>
<script>
'use strict';
// If the originTime parameter passed to the DocumentTimeline exceeds
// the range of the internal storage type (a signed 64-bit integer number
// of ticks--a platform-dependent unit) then we should throw.
// Infinity isn't allowed as an origin time value and clamping to just
// inside the allowed range will just mean we overflow elsewhere.
test(function(t) {
assert_throws({name: 'TypeError'},
function() { new DocumentTimeline(Number.MAX_SAFE_INTEGER); });
}, 'Calculated current time is positive infinity');
test(function(t) {
assert_throws({name: 'TypeError'},
function() { new DocumentTimeline(-1 * Number.MAX_SAFE_INTEGER); });
}, 'Calculated current time is negative infinity');
done();
</script>
</body>

View File

@ -0,0 +1,14 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
'use strict';
setup({explicit_done: true});
SpecialPowers.pushPrefEnv(
{ "set": [["dom.animations-api.core.enabled", true]]},
function() {
window.open("file_document-timeline-origin-time-range.html");
});
</script>

View File

@ -15,6 +15,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/dom/Promise.h"
#include "nsContentUtils.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -409,18 +410,23 @@ ScreenOrientation::UnlockDeviceOrientation()
OrientationType
ScreenOrientation::DeviceType() const
{
return mType;
return ShouldResistFingerprinting() ? OrientationType::Landscape_primary
: mType;
}
uint16_t
ScreenOrientation::DeviceAngle() const
{
return mAngle;
return ShouldResistFingerprinting() ? 0 : mAngle;
}
OrientationType
ScreenOrientation::GetType(ErrorResult& aRv) const
{
if (ShouldResistFingerprinting()) {
return OrientationType::Landscape_primary;
}
nsIDocument* doc = GetResponsibleDocument();
if (!doc) {
aRv.Throw(NS_ERROR_UNEXPECTED);
@ -433,6 +439,10 @@ ScreenOrientation::GetType(ErrorResult& aRv) const
uint16_t
ScreenOrientation::GetAngle(ErrorResult& aRv) const
{
if (ShouldResistFingerprinting()) {
return 0;
}
nsIDocument* doc = GetResponsibleDocument();
if (!doc) {
aRv.Throw(NS_ERROR_UNEXPECTED);
@ -495,6 +505,10 @@ ScreenOrientation::GetResponsibleDocument() const
void
ScreenOrientation::Notify(const hal::ScreenConfiguration& aConfiguration)
{
if (ShouldResistFingerprinting()) {
return;
}
nsIDocument* doc = GetResponsibleDocument();
if (!doc) {
return;
@ -571,6 +585,16 @@ ScreenOrientation::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return ScreenOrientationBinding::Wrap(aCx, this, aGivenProto);
}
bool
ScreenOrientation::ShouldResistFingerprinting() const
{
bool resist = false;
if (nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner()) {
resist = nsContentUtils::ShouldResistFingerprinting(owner->GetDocShell());
}
return resist;
}
NS_IMPL_ISUPPORTS(ScreenOrientation::VisibleEventListener, nsIDOMEventListener)
NS_IMETHODIMP

View File

@ -102,6 +102,8 @@ private:
void DispatchChangeEvent();
bool ShouldResistFingerprinting() const;
LockPermission GetLockOrientationPermission(bool aCheckSandbox) const;
// Gets the responsible document as defined in the spec.

View File

@ -3241,7 +3241,7 @@ DocumentTimeline*
nsDocument::Timeline()
{
if (!mDocumentTimeline) {
mDocumentTimeline = new DocumentTimeline(this);
mDocumentTimeline = new DocumentTimeline(this, TimeDuration(0));
}
return mDocumentTimeline;

View File

@ -13243,8 +13243,8 @@ void
nsGlobalWindow::EnableOrientationChangeListener()
{
MOZ_ASSERT(IsInnerWindow());
if (!mOrientationChangeObserver) {
if (!nsContentUtils::ShouldResistFingerprinting(mDocShell) &&
!mOrientationChangeObserver) {
mOrientationChangeObserver =
new WindowOrientationObserver(this);
}
@ -14087,7 +14087,8 @@ nsGlobalWindow::IsModalContentWindow(JSContext* aCx, JSObject* aGlobal)
int16_t
nsGlobalWindow::Orientation() const
{
return WindowOrientationObserver::OrientationAngle();
return nsContentUtils::ShouldResistFingerprinting(mDocShell) ?
0 : WindowOrientationObserver::OrientationAngle();
}
#endif

View File

@ -1842,8 +1842,23 @@ ValidateCurrentNode(nsRange* aRange, RangeSubtreeIterator& aIter)
}
nsresult res = nsRange::CompareNodeToRange(node, aRange, &before, &after);
NS_ENSURE_SUCCESS(res, false);
return NS_SUCCEEDED(res) && !before && !after;
if (before || after) {
nsCOMPtr<nsIDOMCharacterData> charData = do_QueryInterface(node);
if (charData) {
// If we're dealing with the start/end container which is a character
// node, pretend that the node is in the range.
if (before && node == aRange->GetStartParent()) {
before = false;
}
if (after && node == aRange->GetEndParent()) {
after = false;
}
}
}
return !before && !after;
}
nsresult

View File

@ -193,25 +193,21 @@ nsScreen::Orientation() const
void
nsScreen::GetMozOrientation(nsString& aOrientation) const
{
if (ShouldResistFingerprinting()) {
switch (mScreenOrientation->DeviceType()) {
case OrientationType::Portrait_primary:
aOrientation.AssignLiteral("portrait-primary");
break;
case OrientationType::Portrait_secondary:
aOrientation.AssignLiteral("portrait-secondary");
break;
case OrientationType::Landscape_primary:
aOrientation.AssignLiteral("landscape-primary");
} else {
switch (mScreenOrientation->DeviceType()) {
case OrientationType::Portrait_primary:
aOrientation.AssignLiteral("portrait-primary");
break;
case OrientationType::Portrait_secondary:
aOrientation.AssignLiteral("portrait-secondary");
break;
case OrientationType::Landscape_primary:
aOrientation.AssignLiteral("landscape-primary");
break;
case OrientationType::Landscape_secondary:
aOrientation.AssignLiteral("landscape-secondary");
break;
default:
MOZ_CRASH("Unacceptable screen orientation type.");
}
break;
case OrientationType::Landscape_secondary:
aOrientation.AssignLiteral("landscape-secondary");
break;
default:
MOZ_CRASH("Unacceptable screen orientation type.");
}
}
@ -263,6 +259,9 @@ bool
nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
ErrorResult& aRv)
{
if (ShouldResistFingerprinting()) {
return false;
}
ScreenOrientationInternal orientation = eScreenOrientation_None;
for (uint32_t i = 0; i < aOrientations.Length(); ++i) {
@ -310,6 +309,9 @@ nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations,
void
nsScreen::MozUnlockOrientation()
{
if (ShouldResistFingerprinting()) {
return;
}
UpdateDocShellOrientationLock(GetOwner(), eScreenOrientation_None);
mScreenOrientation->UnlockDeviceOrientation();
}

View File

@ -22,6 +22,8 @@ var test = function (isContent) {
["screen.availTop", 0],
["screen.width", "innerWidth"],
["screen.height", "innerHeight"],
["screen.orientation.type", "'landscape-primary'"],
["screen.orientation.angle", 0],
["screen.mozOrientation", "'landscape-primary'"],
["devicePixelRatio", 1]
];

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script>
window.onload = function() {
setTimeout(function() {
var rng = document.createRange();
rng.setStart(document.getElementsByTagName("p").item(0).firstChild, 100);
rng.setEndAfter(document.getElementsByTagName("p").item(0));
try {
rng.extractContents();
opener.ok(true, "extractContents should not throw when document in iframe is being modified.");
} catch(ex) {
opener.ok(false, "extractContents shouldn't have thrown: " + ex);
}
opener.setTimeout("SimpleTest.finish();", 0);
window.close();
}, 0);
};
</script>
</head>
<body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur elit nisi, convallis sed scelerisque sit amet, vestibulum eu odio. Pellentesque et quam et nibh sollicitudin rutrum. Fusce tristique hendrerit ligula, et euismod sapien facilisis quis. Donec tincidunt turpis tortor, in pharetra tellus euismod ac. Vestibulum consectetur nulla lacinia, consectetur mauris ac, tempus libero. Nam non dui id enim dapibus porta id sed lectus. Praesent at suscipit neque. Vestibulum tellus lorem, placerat et volutpat sed, elementum eget lacus. Sed interdum nisi et imperdiet varius. Sed non magna odio. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus velit risus, accumsan nec efficitur nec, semper sed arcu. Praesent consectetur lectus justo, fringilla imperdiet neque lobortis id. Donec efficitur pulvinar finibus.
<iframe src="data:text/html,<script>window.onunload = function() {document.removeChild(document.documentElement); }</script>" width="10" height="10"></iframe>
</p>
<p>test</p>
</body>
</html>

View File

@ -160,6 +160,7 @@ support-files =
file_bug945152.jar
file_bug1263696_frame_pass.html
file_bug1263696_frame_fail.html
file_bug1274806.html
file_general_document.html
file_html_in_xhr.html
file_html_in_xhr.sjs
@ -664,6 +665,7 @@ skip-if = buildapp == 'b2g'
[test_bug1250148.html]
[test_bug1259588.html]
[test_bug1263696.html]
[test_bug1274806.html]
[test_caretPositionFromPoint.html]
[test_change_policy.html]
skip-if = buildapp == 'b2g' #no ssl support

View File

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1274806
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1274806</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
/** Test for Bug 1274806 **/
function test() {
window.testWindow = window.open("file_bug1274806.html", "", "");
};
</script>
</head>
<body onload="setTimeout(test, 0);">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1274806">Mozilla Bug 1274806</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -98,4 +98,5 @@ MSG_DEF(MSG_INVALID_EASING_ERROR, 1, JSEXN_TYPEERR, "Invalid easing '{0}'.")
MSG_DEF(MSG_USELESS_SETTIMEOUT, 1, JSEXN_TYPEERR, "Useless {0} call (missing quotes around argument?)")
MSG_DEF(MSG_TOKENLIST_NO_SUPPORTED_TOKENS, 2, JSEXN_TYPEERR, "{0} attribute of <{1}> does not define any supported tokens")
MSG_DEF(MSG_CACHE_STREAM_CLOSED, 0, JSEXN_TYPEERR, "Response body is a cache file stream that has already been closed.")
MSG_DEF(MSG_TIME_VALUE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "{0} is outside the supported range for time values.")
MSG_DEF(MSG_ONLY_IF_CACHED_WITHOUT_SAME_ORIGIN, 1, JSEXN_TYPEERR, "Request mode '{0}' was used, but request cache mode 'only-if-cached' can only be used with request mode 'same-origin'.")

View File

@ -791,10 +791,11 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
}
if (mSeekTargetThreshold.isSome()) {
media::TimeUnit pts = GetSampleTime(sample);
if (!pts.IsValid()) {
media::TimeUnit duration = GetSampleDuration(sample);
if (!pts.IsValid() || !duration.IsValid()) {
return E_FAIL;
}
if (pts < mSeekTargetThreshold.ref()) {
if ((pts + duration) < mSeekTargetThreshold.ref()) {
LOG("Dropping video frame which pts is smaller than seek target.");
// It is necessary to clear the pointer to release the previous output
// buffer.

View File

@ -163,6 +163,7 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
case nsIContentPolicy::TYPE_WEBSOCKET:
case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
case nsIContentPolicy::TYPE_BEACON:
case nsIContentPolicy::TYPE_PING:
case nsIContentPolicy::TYPE_FETCH:
return nsIContentSecurityPolicy::CONNECT_SRC_DIRECTIVE;
@ -171,7 +172,6 @@ CSP_ContentTypeToDirective(nsContentPolicyType aType)
return nsIContentSecurityPolicy::OBJECT_SRC_DIRECTIVE;
case nsIContentPolicy::TYPE_XBL:
case nsIContentPolicy::TYPE_PING:
case nsIContentPolicy::TYPE_DTD:
case nsIContentPolicy::TYPE_OTHER:
return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;

View File

@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1100181 - CSP: Enforce connect-src when submitting pings</title>
</head>
<body>
<!-- we are using an image for the test, but can be anything -->
<a id="testlink"
href="http://mochi.test:8888/tests/image/test/mochitest/blue.png"
ping="http://mochi.test:8888/tests/image/test/mochitest/blue.png?send-ping">
Send ping
</a>
<script type="text/javascript">
var link = document.getElementById("testlink");
link.click();
</script>
</body>
</html>

View File

@ -162,6 +162,7 @@ support-files =
file_form_action_server.sjs
!/image/test/mochitest/blue.png
file_meta_whitespace_skipping.html
file_ping.html
[test_base-uri.html]
[test_blob_data_schemes.html]
@ -248,3 +249,4 @@ tags = mcb
tags = mcb
[test_form_action_blocks_url.html]
[test_meta_whitespace_skipping.html]
[test_ping.html]

View File

@ -0,0 +1,103 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1100181 - CSP: Enforce connect-src when submitting pings</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe style="width:100%;" id="testframe"></iframe>
<script class="testbody" type="text/javascript">
/*
* Description of the test:
* We load a page with a given CSP and verify that hyperlink auditing
* is correctly evaluated through the "connect-src" directive.
*/
// Need to pref hyperlink auditing on since it's disabled by default.
SpecialPowers.setBoolPref("browser.send_pings", true);
SimpleTest.waitForExplicitFinish();
var tests = [
{
result : "allowed",
policy : "connect-src 'self'"
},
{
result : "blocked",
policy : "connect-src 'none'"
}
];
// initializing to -1 so we start at index 0 when we start the test
var counter = -1;
function checkResult(aResult) {
is(aResult, tests[counter].result, "should be " + tests[counter].result + " in test " + counter + "!");
loadNextTest();
}
// We use the examiner to identify requests that hit the wire and requests
// that are blocked by CSP and bubble up the result to the including iframe
// document (parent).
function examiner() {
SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
SpecialPowers.addObserver(this, "specialpowers-http-notify-request", false);
}
examiner.prototype = {
observe: function(subject, topic, data) {
if (topic === "specialpowers-http-notify-request") {
// making sure we do not bubble a result for something
// other then the request in question.
if (!data.includes("send-ping")) {
return;
}
checkResult("allowed");
return;
}
if (topic === "csp-on-violate-policy") {
// making sure we do not bubble a result for something
// other then the request in question.
var asciiSpec = SpecialPowers.getPrivilegedProps(
SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
if (!asciiSpec.includes("send-ping")) {
return;
}
checkResult("blocked");
}
},
remove: function() {
SpecialPowers.removeObserver(this, "csp-on-violate-policy");
SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
}
}
window.ConnectSrcExaminer = new examiner();
function loadNextTest() {
counter++;
if (counter == tests.length) {
window.ConnectSrcExaminer.remove();
SimpleTest.finish();
return;
}
var src = "file_testserver.sjs";
// append the file that should be served
src += "?file=" + escape("tests/dom/security/test/csp/file_ping.html");
// append the CSP that should be used to serve the file
src += "&csp=" + escape(tests[counter].policy);
document.getElementById("testframe").src = src;
}
// start running the tests
loadNextTest();
</script>
</body>
</html>

View File

@ -10,8 +10,7 @@
* liability, trademark and document use rules apply.
*/
// Not yet implemented:
// [Constructor (DOMHighResTimeStamp originTime)]
[Func="nsDocument::IsWebAnimationsEnabled"]
[Func="nsDocument::IsWebAnimationsEnabled",
Constructor (DOMHighResTimeStamp originTime)]
interface DocumentTimeline : AnimationTimeline {
};

View File

@ -852,4 +852,11 @@ gfxPlatformGtk::CreateHardwareVsyncSource()
return gfxPlatform::CreateHardwareVsyncSource();
}
bool
gfxPlatformGtk::SupportsApzTouchInput() const
{
int value = gfxPrefs::TouchEventsEnabled();
return value == 1 || value == 2;
}
#endif

View File

@ -123,6 +123,8 @@ public:
return true;
}
bool SupportsApzTouchInput() const override;
void FontsPrefsChanged(const char *aPref) override;
// maximum number of fonts to substitute for a generic

View File

@ -429,7 +429,8 @@ Decoder::PostFrameStop(Opacity aFrameOpacity
DisposalMethod aDisposalMethod
/* = DisposalMethod::KEEP */,
int32_t aTimeout /* = 0 */,
BlendMethod aBlendMethod /* = BlendMethod::OVER */)
BlendMethod aBlendMethod /* = BlendMethod::OVER */,
const Maybe<nsIntRect>& aBlendRect /* = Nothing() */)
{
// We should be mid-frame
MOZ_ASSERT(!IsMetadataDecode(), "Stopping frame during metadata decode");
@ -439,7 +440,8 @@ Decoder::PostFrameStop(Opacity aFrameOpacity
// Update our state
mInFrame = false;
mCurrentFrame->Finish(aFrameOpacity, aDisposalMethod, aTimeout, aBlendMethod);
mCurrentFrame->Finish(aFrameOpacity, aDisposalMethod, aTimeout,
aBlendMethod, aBlendRect);
mProgress |= FLAG_FRAME_COMPLETE;

View File

@ -332,7 +332,8 @@ protected:
void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
int32_t aTimeout = 0,
BlendMethod aBlendMethod = BlendMethod::OVER);
BlendMethod aBlendMethod = BlendMethod::OVER,
const Maybe<nsIntRect>& aBlendRect = Nothing());
/**
* Called by the decoders when they have a region to invalidate. We may not

View File

@ -625,7 +625,8 @@ FrameAnimator::DoBlend(nsIntRect* aDirtyRect,
prevFrameData.mHasAlpha,
compositingFrameData.mRawData,
compositingFrameData.mRect,
prevFrameData.mBlendMethod);
prevFrameData.mBlendMethod,
prevFrameData.mBlendRect);
}
}
}
@ -673,7 +674,8 @@ FrameAnimator::DoBlend(nsIntRect* aDirtyRect,
nextFrameData.mHasAlpha,
compositingFrameData.mRawData,
compositingFrameData.mRect,
nextFrameData.mBlendMethod);
nextFrameData.mBlendMethod,
nextFrameData.mBlendRect);
// Tell the image that it is fully 'downloaded'.
mCompositingFrame->Finish();
@ -742,7 +744,7 @@ nsresult
FrameAnimator::DrawFrameTo(const uint8_t* aSrcData, const nsIntRect& aSrcRect,
uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
uint8_t* aDstPixels, const nsIntRect& aDstRect,
BlendMethod aBlendMethod)
BlendMethod aBlendMethod, const Maybe<nsIntRect>& aBlendRect)
{
NS_ENSURE_ARG_POINTER(aSrcData);
NS_ENSURE_ARG_POINTER(aDstPixels);
@ -822,16 +824,53 @@ FrameAnimator::DrawFrameTo(const uint8_t* aSrcData, const nsIntRect& aSrcRect,
return NS_ERROR_OUT_OF_MEMORY;
}
// XXX(seth): This is inefficient but we'll remove it quite soon when we
// move frame compositing into SurfacePipe. For now we need this because
// RemoveFrameRectFilter has transformed PNG frames with frame rects into
// imgFrame's with no frame rects, but with a region of 0 alpha where the
// frame rect should be. This works really nicely if we're using
// BlendMethod::OVER, but BlendMethod::SOURCE will result in that frame rect
// area overwriting the previous frame, which makes the animation look
// wrong. This quick hack fixes that by first compositing the whle new frame
// with BlendMethod::OVER, and then recopying the area that uses
// BlendMethod::SOURCE if needed. To make this work, the decoder has to
// provide a "blend rect" that tells us where to do this. This is just the
// frame rect, but hidden in a way that makes it invisible to most of the
// system, so we can keep eliminating dependencies on it.
auto op = aBlendMethod == BlendMethod::SOURCE ? PIXMAN_OP_SRC
: PIXMAN_OP_OVER;
pixman_image_composite32(op,
src,
nullptr,
dst,
0, 0,
0, 0,
aSrcRect.x, aSrcRect.y,
aSrcRect.width, aSrcRect.height);
if (aBlendMethod == BlendMethod::OVER || !aBlendRect ||
(aBlendMethod == BlendMethod::SOURCE && aSrcRect.IsEqualEdges(*aBlendRect))) {
// We don't need to do anything clever. (Or, in the case where no blend
// rect was specified, we can't.)
pixman_image_composite32(op,
src,
nullptr,
dst,
0, 0,
0, 0,
aSrcRect.x, aSrcRect.y,
aSrcRect.width, aSrcRect.height);
} else {
// We need to do the OVER followed by SOURCE trick above.
pixman_image_composite32(PIXMAN_OP_OVER,
src,
nullptr,
dst,
0, 0,
0, 0,
aSrcRect.x, aSrcRect.y,
aSrcRect.width, aSrcRect.height);
pixman_image_composite32(PIXMAN_OP_SRC,
src,
nullptr,
dst,
aBlendRect->x, aBlendRect->y,
0, 0,
aBlendRect->x, aBlendRect->y,
aBlendRect->width, aBlendRect->height);
}
pixman_image_unref(src);
pixman_image_unref(dst);

View File

@ -7,6 +7,7 @@
#ifndef mozilla_image_FrameAnimator_h
#define mozilla_image_FrameAnimator_h
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/TimeStamp.h"
#include "gfx2DGlue.h"
@ -246,7 +247,8 @@ private: // methods
const nsIntRect& aSrcRect,
uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
uint8_t* aDstPixels, const nsIntRect& aDstRect,
BlendMethod aBlendMethod);
BlendMethod aBlendMethod,
const Maybe<nsIntRect>& aBlendRect);
private: // data
//! A weak pointer to our owning image.

View File

@ -32,13 +32,13 @@ struct ShutdownObserver : public nsIObserver
NS_IMETHOD Observe(nsISupports*, const char* aTopic, const char16_t*) override
{
if (strcmp(aTopic, "xpcom-shutdown") != 0) {
if (strcmp(aTopic, "xpcom-will-shutdown") != 0) {
return NS_OK;
}
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->RemoveObserver(this, "xpcom-shutdown");
os->RemoveObserver(this, "xpcom-will-shutdown");
}
sShutdownHasStarted = true;
@ -61,7 +61,7 @@ ShutdownTracker::Initialize()
{
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->AddObserver(new ShutdownObserver, "xpcom-shutdown", false);
os->AddObserver(new ShutdownObserver, "xpcom-will-shutdown", false);
}
}

View File

@ -17,8 +17,8 @@ namespace image {
/**
* ShutdownTracker is an imagelib-global service that allows callers to check
* whether shutdown has started. It exists to avoid the need for registering
* many 'xpcom-shutdown' notification observers on short-lived objects, which
* would have an unnecessary performance cost.
* many 'xpcom-will-shutdown' notification observers on short-lived objects,
* which would have an unnecessary performance cost.
*/
struct ShutdownTracker
{

View File

@ -12,6 +12,7 @@
#ifndef mozilla_image_SurfaceFilters_h
#define mozilla_image_SurfaceFilters_h
#include <algorithm>
#include <stdint.h>
#include <string.h>
@ -530,6 +531,362 @@ private:
/// that we're currently writing.
};
//////////////////////////////////////////////////////////////////////////////
// ADAM7InterpolatingFilter
//////////////////////////////////////////////////////////////////////////////
template <typename Next> class ADAM7InterpolatingFilter;
/**
* A configuration struct for ADAM7InterpolatingFilter.
*/
struct ADAM7InterpolatingConfig
{
template <typename Next> using Filter = ADAM7InterpolatingFilter<Next>;
};
/**
* ADAM7InterpolatingFilter performs bilinear interpolation over an ADAM7
* interlaced image.
*
* ADAM7 breaks up the image into 8x8 blocks. On each of the 7 passes, a new set
* of pixels in each block receives their final values, according to the
* following pattern:
*
* 1 6 4 6 2 6 4 6
* 7 7 7 7 7 7 7 7
* 5 6 5 6 5 6 5 6
* 7 7 7 7 7 7 7 7
* 3 6 4 6 3 6 4 6
* 7 7 7 7 7 7 7 7
* 5 6 5 6 5 6 5 6
* 7 7 7 7 7 7 7 7
*
* When rendering the pixels that have not yet received their final values, we
* can get much better intermediate results if we interpolate between
* the pixels we *have* gotten so far. This filter performs bilinear
* interpolation by first performing linear interpolation horizontally for each
* "important" row (which we'll define as a row that has received any pixels
* with final values at all) and then performing linear interpolation vertically
* to produce pixel values for rows which aren't important on the current pass.
*
* Note that this filter totally ignores the data which is written to rows which
* aren't important on the current pass! It's fine to write nothing at all for
* these rows, although doing so won't cause any harm.
*
* XXX(seth): In bug 1280552 we'll add a SIMD implementation for this filter.
*
* The 'Next' template parameter specifies the next filter in the chain.
*/
template <typename Next>
class ADAM7InterpolatingFilter final : public SurfaceFilter
{
public:
ADAM7InterpolatingFilter()
: mPass(0) // The current pass, in the range 1..7. Starts at 0 so that
// DoResetToFirstRow() doesn't have to special case the first pass.
, mRow(0)
{ }
template <typename... Rest>
nsresult Configure(const ADAM7InterpolatingConfig& aConfig, Rest... aRest)
{
nsresult rv = mNext.Configure(aRest...);
if (NS_FAILED(rv)) {
return rv;
}
if (mNext.IsValidPalettedPipe()) {
NS_WARNING("ADAM7InterpolatingFilter used with paletted pipe?");
return NS_ERROR_INVALID_ARG;
}
// We have two intermediate buffers, one for the previous row with final
// pixel values and one for the row that the previous filter in the chain is
// currently writing to.
size_t inputWidthInBytes = mNext.InputSize().width * sizeof(uint32_t);
mPreviousRow.reset(new (fallible) uint8_t[inputWidthInBytes]);
if (MOZ_UNLIKELY(!mPreviousRow)) {
return NS_ERROR_OUT_OF_MEMORY;
}
mCurrentRow.reset(new (fallible) uint8_t[inputWidthInBytes]);
if (MOZ_UNLIKELY(!mCurrentRow)) {
return NS_ERROR_OUT_OF_MEMORY;
}
memset(mPreviousRow.get(), 0, inputWidthInBytes);
memset(mCurrentRow.get(), 0, inputWidthInBytes);
ConfigureFilter(mNext.InputSize(), sizeof(uint32_t));
return NS_OK;
}
Maybe<SurfaceInvalidRect> TakeInvalidRect() override
{
return mNext.TakeInvalidRect();
}
protected:
uint8_t* DoResetToFirstRow() override
{
mRow = 0;
mPass = std::min(mPass + 1, 7);
uint8_t* rowPtr = mNext.ResetToFirstRow();
if (mPass == 7) {
// Short circuit this filter on the final pass, since all pixels have
// their final values at that point.
return rowPtr;
}
return mCurrentRow.get();
}
uint8_t* DoAdvanceRow() override
{
MOZ_ASSERT(0 < mPass && mPass <= 7, "Invalid pass");
int32_t currentRow = mRow;
++mRow;
if (mPass == 7) {
// On the final pass we short circuit this filter totally.
return mNext.AdvanceRow();
}
const int32_t lastImportantRow = LastImportantRow(InputSize().height, mPass);
if (currentRow > lastImportantRow) {
return nullptr; // This pass is already complete.
}
if (!IsImportantRow(currentRow, mPass)) {
// We just ignore whatever the caller gives us for these rows. We'll
// interpolate them in later.
return mCurrentRow.get();
}
// This is an important row. We need to perform horizontal interpolation for
// these rows.
InterpolateHorizontally(mCurrentRow.get(), InputSize().width, mPass);
// Interpolate vertically between the previous important row and the current
// important row. We skip this if the current row is 0 (which is always an
// important row), because in that case there is no previous important row
// to interpolate with.
if (currentRow != 0) {
InterpolateVertically(mPreviousRow.get(), mCurrentRow.get(), mPass, mNext);
}
// Write out the current row itself, which, being an important row, does not
// need vertical interpolation.
uint32_t* currentRowAsPixels = reinterpret_cast<uint32_t*>(mCurrentRow.get());
mNext.WriteBuffer(currentRowAsPixels);
if (currentRow == lastImportantRow) {
// This is the last important row, which completes this pass. Note that
// for very small images, this may be the first row! Since there won't be
// another important row, there's nothing to interpolate with vertically,
// so we just duplicate this row until the end of the image.
while (mNext.WriteBuffer(currentRowAsPixels) == WriteState::NEED_MORE_DATA) { }
// All of the remaining rows in the image were determined above, so we're done.
return nullptr;
}
// The current row is now the previous important row; save it.
Swap(mPreviousRow, mCurrentRow);
MOZ_ASSERT(mRow < InputSize().height, "Reached the end of the surface without "
"hitting the last important row?");
return mCurrentRow.get();
}
private:
static void InterpolateVertically(uint8_t* aPreviousRow,
uint8_t* aCurrentRow,
uint8_t aPass,
SurfaceFilter& aNext)
{
const float* weights = InterpolationWeights(ImportantRowStride(aPass));
// We need to interpolate vertically to generate the rows between the
// previous important row and the next one. Recall that important rows are
// rows which contain at least some final pixels; see
// InterpolateHorizontally() for some additional explanation as to what that
// means. Note that we've already written out the previous important row, so
// we start the iteration at 1.
for (int32_t outRow = 1; outRow < ImportantRowStride(aPass); ++outRow) {
const float weight = weights[outRow];
// We iterate through the previous and current important row every time we
// write out an interpolated row, so we need to copy the pointers.
uint8_t* prevRowBytes = aPreviousRow;
uint8_t* currRowBytes = aCurrentRow;
// Write out the interpolated pixels. Interpolation is componentwise.
aNext.template WritePixelsToRow<uint32_t>([&]{
uint32_t pixel = 0;
auto* component = reinterpret_cast<uint8_t*>(&pixel);
*component++ = InterpolateByte(*prevRowBytes++, *currRowBytes++, weight);
*component++ = InterpolateByte(*prevRowBytes++, *currRowBytes++, weight);
*component++ = InterpolateByte(*prevRowBytes++, *currRowBytes++, weight);
*component++ = InterpolateByte(*prevRowBytes++, *currRowBytes++, weight);
return AsVariant(pixel);
});
}
}
static void InterpolateHorizontally(uint8_t* aRow, int32_t aWidth, uint8_t aPass)
{
// Collect the data we'll need to perform horizontal interpolation. The
// terminology here bears some explanation: a "final pixel" is a pixel which
// has received its final value. On each pass, a new set of pixels receives
// their final value; see the diagram above of the 8x8 pattern that ADAM7
// uses. Any pixel which hasn't received its final value on this pass
// derives its value from either horizontal or vertical interpolation
// instead.
const size_t finalPixelStride = FinalPixelStride(aPass);
const size_t finalPixelStrideBytes = finalPixelStride * sizeof(uint32_t);
const size_t lastFinalPixel = LastFinalPixel(aWidth, aPass);
const size_t lastFinalPixelBytes = lastFinalPixel * sizeof(uint32_t);
const float* weights = InterpolationWeights(finalPixelStride);
// Interpolate blocks of pixels which lie between two final pixels.
// Horizontal interpolation is done in place, as we'll need the results
// later when we vertically interpolate.
for (size_t blockBytes = 0;
blockBytes < lastFinalPixelBytes;
blockBytes += finalPixelStrideBytes) {
uint8_t* finalPixelA = aRow + blockBytes;
uint8_t* finalPixelB = aRow + blockBytes + finalPixelStrideBytes;
MOZ_ASSERT(finalPixelA < aRow + aWidth * sizeof(uint32_t),
"Running off end of buffer");
MOZ_ASSERT(finalPixelB < aRow + aWidth * sizeof(uint32_t),
"Running off end of buffer");
// Interpolate the individual pixels componentwise. Note that we start
// iteration at 1 since we don't need to apply any interpolation to the
// first pixel in the block, which has its final value.
for (size_t pixelIndex = 1; pixelIndex < finalPixelStride; ++pixelIndex) {
const float weight = weights[pixelIndex];
uint8_t* pixel = aRow + blockBytes + pixelIndex * sizeof(uint32_t);
MOZ_ASSERT(pixel < aRow + aWidth * sizeof(uint32_t), "Running off end of buffer");
for (size_t component = 0; component < sizeof(uint32_t); ++component) {
pixel[component] =
InterpolateByte(finalPixelA[component], finalPixelB[component], weight);
}
}
}
// For the pixels after the last final pixel in the row, there isn't a
// second final pixel to interpolate with, so just duplicate.
uint32_t* rowPixels = reinterpret_cast<uint32_t*>(aRow);
uint32_t pixelToDuplicate = rowPixels[lastFinalPixel];
for (int32_t pixelIndex = lastFinalPixel + 1;
pixelIndex < aWidth;
++pixelIndex) {
MOZ_ASSERT(pixelIndex < aWidth, "Running off end of buffer");
rowPixels[pixelIndex] = pixelToDuplicate;
}
}
static uint8_t InterpolateByte(uint8_t aByteA, uint8_t aByteB, float aWeight)
{
return uint8_t(aByteA * aWeight + aByteB * (1.0f - aWeight));
}
static int32_t ImportantRowStride(uint8_t aPass)
{
MOZ_ASSERT(0 < aPass && aPass <= 7, "Invalid pass");
// The stride between important rows for each pass, with a dummy value for
// the nonexistent pass 0.
static int32_t strides[] = { 1, 8, 8, 4, 4, 2, 2, 1 };
return strides[aPass];
}
static bool IsImportantRow(int32_t aRow, uint8_t aPass)
{
MOZ_ASSERT(aRow >= 0);
// Whether the row is important comes down to divisibility by the stride for
// this pass, which is always a power of 2, so we can check using a mask.
int32_t mask = ImportantRowStride(aPass) - 1;
return (aRow & mask) == 0;
}
static int32_t LastImportantRow(int32_t aHeight, uint8_t aPass)
{
MOZ_ASSERT(aHeight > 0);
// We can find the last important row using the same mask trick as above.
int32_t lastRow = aHeight - 1;
int32_t mask = ImportantRowStride(aPass) - 1;
return lastRow - (lastRow & mask);
}
static size_t FinalPixelStride(uint8_t aPass)
{
MOZ_ASSERT(0 < aPass && aPass <= 7, "Invalid pass");
// The stride between the final pixels in important rows for each pass, with
// a dummy value for the nonexistent pass 0.
static size_t strides[] = { 1, 8, 4, 4, 2, 2, 1, 1 };
return strides[aPass];
}
static size_t LastFinalPixel(int32_t aWidth, uint8_t aPass)
{
MOZ_ASSERT(aWidth >= 0);
// Again, we can use the mask trick above to find the last important pixel.
int32_t lastColumn = aWidth - 1;
size_t mask = FinalPixelStride(aPass) - 1;
return lastColumn - (lastColumn & mask);
}
static const float* InterpolationWeights(int32_t aStride)
{
// Precalculated interpolation weights. These are used to interpolate
// between final pixels or between important rows. Although no interpolation
// is actually applied to the previous final pixel or important row value,
// the arrays still start with 1.0f, which is always skipped, primarily
// because otherwise |stride1Weights| would have zero elements.
static float stride8Weights[] =
{ 1.0f, 7 / 8.0f, 6 / 8.0f, 5 / 8.0f, 4 / 8.0f, 3 / 8.0f, 2 / 8.0f, 1 / 8.0f };
static float stride4Weights[] = { 1.0f, 3 / 4.0f, 2 / 4.0f, 1 / 4.0f };
static float stride2Weights[] = { 1.0f, 1 / 2.0f };
static float stride1Weights[] = { 1.0f };
switch (aStride) {
case 8: return stride8Weights;
case 4: return stride4Weights;
case 2: return stride2Weights;
case 1: return stride1Weights;
default: MOZ_CRASH();
}
}
Next mNext; /// The next SurfaceFilter in the chain.
UniquePtr<uint8_t[]> mPreviousRow; /// The last important row (i.e., row with
/// final pixel values) that got written to.
UniquePtr<uint8_t[]> mCurrentRow; /// The row that's being written to right
/// now.
uint8_t mPass; /// Which ADAM7 pass we're on. Valid passes
/// are 1..7 during processing and 0 prior
/// to configuraiton.
int32_t mRow; /// The row we're currently reading.
};
} // namespace image
} // namespace mozilla

View File

@ -48,9 +48,13 @@ enum class SurfacePipeFlags
{
DEINTERLACE = 1 << 0, // If set, deinterlace the image.
FLIP_VERTICALLY = 1 << 1, // If set, flip the image vertically.
ADAM7_INTERPOLATE = 1 << 1, // If set, the caller is deinterlacing the
// image using ADAM7, and we may want to
// interpolate it for better intermediate results.
PROGRESSIVE_DISPLAY = 1 << 2 // If set, we expect the image to be displayed
FLIP_VERTICALLY = 1 << 2, // If set, flip the image vertically.
PROGRESSIVE_DISPLAY = 1 << 3 // If set, we expect the image to be displayed
// progressively. This enables features that
// result in a better user experience for
// progressive display but which may be more
@ -99,12 +103,26 @@ public:
const bool removeFrameRect =
!aFrameRect.IsEqualEdges(nsIntRect(0, 0, aInputSize.width, aInputSize.height));
// Don't interpolate if we're sure we won't show this surface to the user
// until it's completely decoded. The final pass of an ADAM7 image doesn't
// need interpolation, so we only need to interpolate if we'll be displaying
// the image while it's still being decoded.
const bool adam7Interpolate = bool(aFlags & SurfacePipeFlags::ADAM7_INTERPOLATE) &&
progressiveDisplay;
if (deinterlace && adam7Interpolate) {
MOZ_ASSERT_UNREACHABLE("ADAM7 deinterlacing is handled by libpng");
return Nothing();
}
// Construct configurations for the SurfaceFilters. Note that the order of
// these filters is significant. We want to deinterlace raw input rows,
// before any other transformations, and we want to remove the frame rect
// (which may involve adding blank rows or columns to the image) before any
// downscaling, so that the new rows and columns are taken into account.
// these filters is significant. We want to deinterlace or interpolate raw
// input rows, before any other transformations, and we want to remove the
// frame rect (which may involve adding blank rows or columns to the image)
// before any downscaling, so that the new rows and columns are taken into
// account.
DeinterlacingConfig<uint32_t> deinterlacingConfig { progressiveDisplay };
ADAM7InterpolatingConfig interpolatingConfig;
RemoveFrameRectConfig removeFrameRectConfig { aFrameRect };
DownscalingConfig downscalingConfig { aInputSize, aFormat };
SurfaceConfig surfaceConfig { aDecoder, aFrameNum, aOutputSize,
@ -117,13 +135,18 @@ public:
if (deinterlace) {
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
downscalingConfig, surfaceConfig);
} else { // (deinterlace is false)
} else if (adam7Interpolate) {
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
downscalingConfig, surfaceConfig);
} else { // (deinterlace and adam7Interpolate are false)
pipe = MakePipe(removeFrameRectConfig, downscalingConfig, surfaceConfig);
}
} else { // (removeFrameRect is false)
if (deinterlace) {
pipe = MakePipe(deinterlacingConfig, downscalingConfig, surfaceConfig);
} else { // (deinterlace is false)
} else if (adam7Interpolate) {
pipe = MakePipe(interpolatingConfig, downscalingConfig, surfaceConfig);
} else { // (deinterlace and adam7Interpolate are false)
pipe = MakePipe(downscalingConfig, surfaceConfig);
}
}
@ -131,13 +154,17 @@ public:
if (removeFrameRect) {
if (deinterlace) {
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, surfaceConfig);
} else { // (deinterlace is false)
} else if (adam7Interpolate) {
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, surfaceConfig);
} else { // (deinterlace and adam7Interpolate are false)
pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
}
} else { // (removeFrameRect is false)
if (deinterlace) {
pipe = MakePipe(deinterlacingConfig, surfaceConfig);
} else { // (deinterlace is false)
} else if (adam7Interpolate) {
pipe = MakePipe(interpolatingConfig, surfaceConfig);
} else { // (deinterlace and adam7Interpolate are false)
pipe = MakePipe(surfaceConfig);
}
}

View File

@ -16,6 +16,8 @@
#include "nspr.h"
#include "png.h"
#include "RasterImage.h"
#include "SurfacePipeFactory.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Telemetry.h"
#include <algorithm>
@ -91,18 +93,23 @@ const uint8_t
nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
nsPNGDecoder::nsPNGDecoder(RasterImage* aImage)
: Decoder(aImage),
mPNG(nullptr), mInfo(nullptr),
mCMSLine(nullptr), interlacebuf(nullptr),
mInProfile(nullptr), mTransform(nullptr),
format(gfx::SurfaceFormat::UNKNOWN),
mHeaderBytesRead(0), mCMSMode(0),
mChannels(0), mFrameIsHidden(false),
mDisablePremultipliedAlpha(false),
mSuccessfulEarlyFinish(false),
mNumFrames(0)
{
}
: Decoder(aImage)
, mPNG(nullptr)
, mInfo(nullptr)
, mCMSLine(nullptr)
, interlacebuf(nullptr)
, mInProfile(nullptr)
, mTransform(nullptr)
, format(gfx::SurfaceFormat::UNKNOWN)
, mHeaderBytesRead(0)
, mCMSMode(0)
, mChannels(0)
, mPass(0)
, mFrameIsHidden(false)
, mDisablePremultipliedAlpha(false)
, mSuccessfulEarlyFinish(false)
, mNumFrames(0)
{ }
nsPNGDecoder::~nsPNGDecoder()
{
@ -125,55 +132,98 @@ nsPNGDecoder::~nsPNGDecoder()
}
}
void
nsPNGDecoder::CheckForTransparency(SurfaceFormat aFormat,
const IntRect& aFrameRect)
nsPNGDecoder::TransparencyType
nsPNGDecoder::GetTransparencyType(SurfaceFormat aFormat,
const IntRect& aFrameRect)
{
// Check if the image has a transparent color in its palette.
if (aFormat == SurfaceFormat::B8G8R8A8) {
PostHasTransparency();
return TransparencyType::eAlpha;
}
if (!IntRect(IntPoint(), GetSize()).IsEqualEdges(aFrameRect)) {
MOZ_ASSERT(HasAnimation());
return TransparencyType::eFrameRect;
}
// If the first frame of animated image doesn't draw into the whole image,
// then record that it is transparent.
if (mNumFrames == 0 && !IntRect(IntPoint(), GetSize()).IsEqualEdges(aFrameRect)) {
MOZ_ASSERT(HasAnimation());
PostHasTransparency();
return TransparencyType::eNone;
}
void
nsPNGDecoder::PostHasTransparencyIfNeeded(TransparencyType aTransparencyType)
{
switch (aTransparencyType) {
case TransparencyType::eNone:
return;
case TransparencyType::eAlpha:
PostHasTransparency();
return;
case TransparencyType::eFrameRect:
// If the first frame of animated image doesn't draw into the whole image,
// then record that it is transparent. For subsequent frames, this doesn't
// affect transparency, because they're composited on top of all previous
// frames.
if (mNumFrames == 0) {
PostHasTransparency();
}
return;
}
}
// CreateFrame() is used for both simple and animated images
// CreateFrame() is used for both simple and animated images.
nsresult
nsPNGDecoder::CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
int32_t aWidth, int32_t aHeight,
gfx::SurfaceFormat aFormat)
nsPNGDecoder::CreateFrame(SurfaceFormat aFormat,
const IntRect& aFrameRect,
bool aIsInterlaced)
{
MOZ_ASSERT(HasSize());
MOZ_ASSERT(!IsMetadataDecode());
IntRect frameRect(aXOffset, aYOffset, aWidth, aHeight);
CheckForTransparency(aFormat, frameRect);
// Check if we have transparency, and send notifications if needed.
auto transparency = GetTransparencyType(aFormat, aFrameRect);
PostHasTransparencyIfNeeded(transparency);
SurfaceFormat format = transparency == TransparencyType::eNone
? SurfaceFormat::B8G8R8X8
: SurfaceFormat::B8G8R8A8;
// Make sure there's no animation or padding if we're downscaling.
MOZ_ASSERT_IF(mDownscaler, mNumFrames == 0);
MOZ_ASSERT_IF(mDownscaler, !GetImageMetadata().HasAnimation());
MOZ_ASSERT_IF(mDownscaler,
IntRect(IntPoint(), GetSize()).IsEqualEdges(frameRect));
MOZ_ASSERT_IF(mDownscaler, transparency != TransparencyType::eFrameRect);
IntSize targetSize = mDownscaler ? mDownscaler->TargetSize()
: GetSize();
IntRect targetFrameRect = mDownscaler ? IntRect(IntPoint(), targetSize)
: frameRect;
nsresult rv = AllocateFrame(mNumFrames, targetSize, targetFrameRect, aFormat);
if (NS_FAILED(rv)) {
return rv;
// If this image is interlaced, we can display better quality intermediate
// results to the user by post processing them with ADAM7InterpolatingFilter.
SurfacePipeFlags pipeFlags = aIsInterlaced
? SurfacePipeFlags::ADAM7_INTERPOLATE
: SurfacePipeFlags();
if (mNumFrames == 0) {
// The first frame may be displayed progressively.
pipeFlags |= SurfacePipeFlags::PROGRESSIVE_DISPLAY;
}
mFrameRect = frameRect;
Maybe<SurfacePipe> pipe =
SurfacePipeFactory::CreateSurfacePipe(this, mNumFrames, GetSize(), targetSize,
aFrameRect, format, pipeFlags);
if (!pipe) {
mPipe = SurfacePipe();
return NS_ERROR_FAILURE;
}
mPipe = Move(*pipe);
mFrameRect = aFrameRect;
mPass = 0;
MOZ_LOG(sPNGDecoderAccountingLog, LogLevel::Debug,
("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created "
"image frame with %dx%d pixels for decoder %p",
aWidth, aHeight, this));
aFrameRect.width, aFrameRect.height, this));
#ifdef PNG_APNG_SUPPORTED
if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) {
@ -187,15 +237,6 @@ nsPNGDecoder::CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
}
#endif
if (mDownscaler) {
bool hasAlpha = aFormat != SurfaceFormat::B8G8R8X8;
rv = mDownscaler->BeginFrame(frameRect.Size(), Nothing(),
mImageData, hasAlpha);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
@ -215,7 +256,7 @@ nsPNGDecoder::EndImageFrame()
}
PostFrameStop(opacity, mAnimInfo.mDispose, mAnimInfo.mTimeout,
mAnimInfo.mBlend);
mAnimInfo.mBlend, Some(mFrameRect));
}
void
@ -458,7 +499,6 @@ PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr,
void
nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
{
// int number_passes; NOT USED
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, compression_type, filter_type;
unsigned int channels;
@ -478,8 +518,10 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
png_longjmp(decoder->mPNG, 1);
}
const IntRect frameRect(0, 0, width, height);
// Post our size to the superclass
decoder->PostSize(width, height);
decoder->PostSize(frameRect.width, frameRect.height);
if (decoder->HasError()) {
// Setting the size led to an error.
png_longjmp(decoder->mPNG, 1);
@ -564,9 +606,9 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
}
}
// let libpng expand interlaced images
if (interlace_type == PNG_INTERLACE_ADAM7) {
// number_passes =
// Let libpng expand interlaced images.
const bool isInterlaced = interlace_type == PNG_INTERLACE_ADAM7;
if (isInterlaced) {
png_set_interlace_handling(png_ptr);
}
@ -595,7 +637,7 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
if (decoder->mDownscaler && !decoder->IsFirstFrameDecode()) {
MOZ_ASSERT_UNREACHABLE("Doing downscale-during-decode "
"for an animated image?");
decoder->mDownscaler.reset();
png_longjmp(decoder->mPNG, 1); // Abort the decode.
}
}
#endif
@ -607,8 +649,8 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
// call PostHasTransparency in the metadata decode if we need to. So it's okay
// to pass IntRect(0, 0, width, height) here for animated images; they will
// call with the proper first frame rect in the full decode.
decoder->CheckForTransparency(decoder->format,
IntRect(0, 0, width, height));
auto transparency = decoder->GetTransparencyType(decoder->format, frameRect);
decoder->PostHasTransparencyIfNeeded(transparency);
// We have the metadata we're looking for, so we don't need to decode any
// further.
@ -626,7 +668,7 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
decoder->mFrameIsHidden = true;
} else {
#endif
nsresult rv = decoder->CreateFrame(0, 0, width, height, decoder->format);
nsresult rv = decoder->CreateFrame(decoder->format, frameRect, isInterlaced);
if (NS_FAILED(rv)) {
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
}
@ -635,19 +677,19 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
}
#endif
if (decoder->mTransform &&
(channels <= 2 || interlace_type == PNG_INTERLACE_ADAM7)) {
if (decoder->mTransform && (channels <= 2 || isInterlaced)) {
uint32_t bpp[] = { 0, 3, 4, 3, 4 };
decoder->mCMSLine =
(uint8_t*)malloc(bpp[channels] * width);
static_cast<uint8_t*>(malloc(bpp[channels] * frameRect.width));
if (!decoder->mCMSLine) {
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
}
}
if (interlace_type == PNG_INTERLACE_ADAM7) {
if (height < INT32_MAX / (width * channels)) {
decoder->interlacebuf = (uint8_t*)malloc(channels * width * height);
if (frameRect.height < INT32_MAX / (frameRect.width * int32_t(channels))) {
const size_t bufferSize = channels * frameRect.width * frameRect.height;
decoder->interlacebuf = static_cast<uint8_t*>(malloc(bufferSize));
}
if (!decoder->interlacebuf) {
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
@ -656,106 +698,44 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
}
void
nsPNGDecoder::PostPartialInvalidation(const IntRect& aInvalidRegion)
nsPNGDecoder::PostInvalidationIfNeeded()
{
if (!mDownscaler) {
PostInvalidation(aInvalidRegion);
Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
if (!invalidRect) {
return;
}
if (!mDownscaler->HasInvalidation()) {
return;
}
DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect();
PostInvalidation(invalidRect.mOriginalSizeRect,
Some(invalidRect.mTargetSizeRect));
PostInvalidation(invalidRect->mInputSpaceRect,
Some(invalidRect->mOutputSpaceRect));
}
void
nsPNGDecoder::PostFullInvalidation()
static NextPixel<uint32_t>
PackRGBPixelAndAdvance(uint8_t*& aRawPixelInOut)
{
PostInvalidation(mFrameRect);
if (mDownscaler) {
mDownscaler->ResetForNextProgressivePass();
}
const uint32_t pixel =
gfxPackedPixel(0xFF, aRawPixelInOut[0], aRawPixelInOut[1], aRawPixelInOut[2]);
aRawPixelInOut += 3;
return AsVariant(pixel);
}
static void
InterpolateInterlacedPNG(const int aPass, const bool aHasAlpha,
const uint32_t aWidth, const uint32_t aHeight,
uint8_t* aImageData)
static NextPixel<uint32_t>
PackRGBAPixelAndAdvance(uint8_t*& aRawPixelInOut)
{
// At this point we have a completed pass of an interlaced image in
// imageData as an array of uint8_t ARGB or XRGB pixels, optionally
// premultiplied, 4 bytes per pixel. If there are leftover partial
// blocks at the right edge or bottom of the image, we just use the
// uninterpolated pixels that libpng gave us.
//
// See Bug #75077, Interpolation of interlaced PNG
// See https://en.wikipedia.org/wiki/Bilinear_interpolation
//
// Note: this doesn't work when downscaling so we simply show
// the uninterpolated blocks that libpng gives us.
//
// Don't try to interpolate images that are less than 8 columns wide
// or 8 rows high; do only square passes (0, 2, 4)
if ((aPass != 0 && aPass != 2 && aPass != 4) || aWidth < 8 || aHeight < 8) {
return;
}
const uint32_t pixel =
gfxPackedPixel(aRawPixelInOut[3], aRawPixelInOut[0],
aRawPixelInOut[1], aRawPixelInOut[2]);
aRawPixelInOut += 4;
return AsVariant(pixel);
}
/* Block dimensions are defined by the PNG specification */
uint32_t block_width[] = { 8, 4, 4, 2, 2 };
uint32_t bw = block_width[aPass];
uint32_t bh = bw;
bool first_component = aHasAlpha ? 0: 1;
// Reduced version of the PNG_PASS_ROW_SHIFT(pass) macro in libpng/png.h
// Only works with square passes 0, 2, and 4
uint32_t divisor_shift = 3 - (aPass >> 1);
// Loop over blocks
for (uint32_t y = 0; y < aHeight - bh; y += bh) {
for (uint32_t x = 0; x < aWidth - bw; x += bw) {
// (x,y) is the top left corner of the block
// topleft is the first component of the top left pixel of the block
uint8_t* topleft = aImageData + 4 * (x + aWidth * y);
// Loop over component=[A,]R,G,B
for (uint32_t component = first_component; component < 4; component++) {
if (x == 0) {
// Interpolate ARGB along the left side of the block
uint32_t top = *(topleft + component);
uint32_t bottom = *(topleft + component + (bh * 4 * aWidth));
for (uint32_t j = 1; j < bh; j++) {
*(topleft + component + j * 4 * aWidth) =
((top * (bh - j) + bottom * j) >> divisor_shift) & 0xff;
}
}
// Interpolate ARGB along the right side of the block
uint32_t top = *(topleft + component + 4 * bw);
uint32_t bottom = *(topleft + component + 4 * (bw + (bh * aWidth)));
for (uint32_t j = 1; j < bh; j++) {
*(topleft + component + 4 * (bw + j * aWidth)) =
((top * (bh - j) + bottom * j) >> divisor_shift) & 0xff;
}
// Interpolate ARGB in the X-direction along the top edge
// and within the block
for (uint32_t j = 0; j < bh; j++) {
uint32_t left = *(topleft + component + 4 * j * aWidth);
uint32_t right = *(topleft + component + 4 * (bw + j * aWidth));
for (uint32_t i = 1; i < bw; i++) {
*(topleft + component + 4 * (i + j * aWidth)) =
((left * (bw - i) + right * i) >> divisor_shift) & 0xff;
} // i
} // j
} // component
} // x
} // y
static NextPixel<uint32_t>
PackUnpremultipliedRGBAPixelAndAdvance(uint8_t*& aRawPixelInOut)
{
const uint32_t pixel =
gfxPackedPixelNoPreMultiply(aRawPixelInOut[3], aRawPixelInOut[0],
aRawPixelInOut[1], aRawPixelInOut[2]);
aRawPixelInOut += 4;
return AsVariant(pixel);
}
void
@ -790,127 +770,102 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
* old row and the new row.
*/
nsPNGDecoder* decoder =
static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
// skip this frame
if (decoder->mFrameIsHidden) {
return; // Skip this frame.
}
while (pass > decoder->mPass) {
// Advance to the next pass. We may have to do this multiple times because
// libpng will skip passes if the image is so small that no pixels have
// changed on a given pass, but ADAM7InterpolatingFilter needs to be reset
// once for every pass to perform interpolation properly.
decoder->mPipe.ResetToFirstRow();
decoder->mPass++;
}
const png_uint_32 height = static_cast<png_uint_32>(decoder->mFrameRect.height);
if (row_num >= height) {
// Bail if we receive extra rows. This is especially important because if we
// didn't, we might overflow the deinterlacing buffer.
MOZ_ASSERT_UNREACHABLE("libpng producing extra rows?");
return;
}
if (row_num >= static_cast<png_uint_32>(decoder->mFrameRect.height)) {
return;
}
// Note that |new_row| may be null here, indicating that this is an interlaced
// image and |row_callback| is being called for a row that hasn't changed.
MOZ_ASSERT_IF(!new_row, decoder->interlacebuf);
uint8_t* rowToWrite = new_row;
bool lastRow =
row_num == static_cast<png_uint_32>(decoder->mFrameRect.height) - 1;
if (!new_row && !decoder->mDownscaler && !lastRow) {
// If |new_row| is null, that indicates that this is an interlaced image
// and |row_callback| is being called for a row that hasn't changed.
// Ordinarily we don't need to do anything in this case, but if we're
// downscaling, the downscaler doesn't store the rows from previous passes,
// so we still need to process the row. If |lastRow| is true we need
// to finish the interlace pass.
return;
}
int32_t width = decoder->mFrameRect.width;
uint32_t iwidth = decoder->mFrameRect.width;
png_bytep line = new_row;
if (decoder->interlacebuf) {
line = decoder->interlacebuf + (row_num * decoder->mChannels * width);
png_progressive_combine_row(png_ptr, line, new_row);
uint32_t width = uint32_t(decoder->mFrameRect.width);
// We'll output the deinterlaced version of the row.
rowToWrite = decoder->interlacebuf + (row_num * decoder->mChannels * width);
// Update the deinterlaced version of this row with the new data.
png_progressive_combine_row(png_ptr, rowToWrite, new_row);
}
uint32_t bpr = width * sizeof(uint32_t);
uint32_t* cptr32 = decoder->mDownscaler
? reinterpret_cast<uint32_t*>(decoder->mDownscaler->RowBuffer())
: reinterpret_cast<uint32_t*>(decoder->mImageData + (row_num*bpr));
decoder->WriteRow(rowToWrite);
}
if (decoder->mTransform) {
if (decoder->mCMSLine) {
qcms_transform_data(decoder->mTransform, line, decoder->mCMSLine,
iwidth);
// copy alpha over
uint32_t channels = decoder->mChannels;
if (channels == 2 || channels == 4) {
for (uint32_t i = 0; i < iwidth; i++)
decoder->mCMSLine[4 * i + 3] = line[channels * i + channels - 1];
void
nsPNGDecoder::WriteRow(uint8_t* aRow)
{
MOZ_ASSERT(aRow);
uint8_t* rowToWrite = aRow;
uint32_t width = uint32_t(mFrameRect.width);
// Apply color management to the row, if necessary, before writing it out.
if (mTransform) {
if (mCMSLine) {
qcms_transform_data(mTransform, rowToWrite, mCMSLine, width);
// Copy alpha over.
if (mChannels == 2 || mChannels == 4) {
for (uint32_t i = 0; i < width; ++i) {
mCMSLine[4 * i + 3] = rowToWrite[mChannels * i + mChannels - 1];
}
}
line = decoder->mCMSLine;
rowToWrite = mCMSLine;
} else {
qcms_transform_data(decoder->mTransform, line, line, iwidth);
qcms_transform_data(mTransform, rowToWrite, rowToWrite, width);
}
}
switch (decoder->format) {
case gfx::SurfaceFormat::B8G8R8X8: {
// counter for while() loops below
uint32_t idx = iwidth;
// Write this row to the SurfacePipe.
DebugOnly<WriteState> result = WriteState::FAILURE;
switch (format) {
case SurfaceFormat::B8G8R8X8:
result = mPipe.WritePixelsToRow<uint32_t>([&]{
return PackRGBPixelAndAdvance(rowToWrite);
});
break;
// copy as bytes until source pointer is 32-bit-aligned
for (; (NS_PTR_TO_UINT32(line) & 0x3) && idx; --idx) {
*cptr32++ = gfxPackedPixel(0xFF, line[0], line[1], line[2]);
line += 3;
}
// copy pixels in blocks of 4
while (idx >= 4) {
GFX_BLOCK_RGB_TO_FRGB(line, cptr32);
idx -= 4;
line += 12;
cptr32 += 4;
}
// copy remaining pixel(s)
while (idx--) {
// 32-bit read of final pixel will exceed buffer, so read bytes
*cptr32++ = gfxPackedPixel(0xFF, line[0], line[1], line[2]);
line += 3;
}
}
break;
case gfx::SurfaceFormat::B8G8R8A8: {
if (!decoder->mDisablePremultipliedAlpha) {
for (uint32_t x=width; x>0; --x) {
*cptr32++ = gfxPackedPixel(line[3], line[0], line[1], line[2]);
line += 4;
}
case SurfaceFormat::B8G8R8A8:
if (mDisablePremultipliedAlpha) {
result = mPipe.WritePixelsToRow<uint32_t>([&]{
return PackUnpremultipliedRGBAPixelAndAdvance(rowToWrite);
});
} else {
for (uint32_t x=width; x>0; --x) {
*cptr32++ = gfxPackedPixelNoPreMultiply(line[3], line[0], line[1],
line[2]);
line += 4;
}
result = mPipe.WritePixelsToRow<uint32_t>([&]{
return PackRGBAPixelAndAdvance(rowToWrite);
});
}
}
break;
break;
default:
png_longjmp(decoder->mPNG, 1);
png_longjmp(mPNG, 1); // Abort the decode.
}
if (decoder->mDownscaler) {
decoder->mDownscaler->CommitRow();
}
MOZ_ASSERT(WriteState(result) != WriteState::FAILURE);
if (!decoder->interlacebuf) {
// Do line-by-line partial invalidations for non-interlaced images.
decoder->PostPartialInvalidation(IntRect(0, row_num, width, 1));
} else if (lastRow) {
// Do only one full image invalidation for each even pass. (Bug 1187569)
if (decoder->mDownscaler) {
decoder->PostFullInvalidation();
} else if (pass % 2 == 0) {
const bool hasAlpha = decoder->format != SurfaceFormat::B8G8R8X8;
InterpolateInterlacedPNG(pass, hasAlpha,
static_cast<uint32_t>(width),
decoder->mFrameRect.height,
decoder->mImageData);
decoder->PostFullInvalidation();
}
}
PostInvalidationIfNeeded();
}
#ifdef PNG_APNG_SUPPORTED
@ -918,9 +873,6 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
void
nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
{
png_uint_32 x_offset, y_offset;
int32_t width, height;
nsPNGDecoder* decoder =
static_cast<nsPNGDecoder*>(png_get_progressive_ptr(png_ptr));
@ -938,13 +890,14 @@ nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
// Only the first frame can be hidden, so unhide unconditionally here.
decoder->mFrameIsHidden = false;
x_offset = png_get_next_frame_x_offset(png_ptr, decoder->mInfo);
y_offset = png_get_next_frame_y_offset(png_ptr, decoder->mInfo);
width = png_get_next_frame_width(png_ptr, decoder->mInfo);
height = png_get_next_frame_height(png_ptr, decoder->mInfo);
const IntRect frameRect(png_get_next_frame_x_offset(png_ptr, decoder->mInfo),
png_get_next_frame_y_offset(png_ptr, decoder->mInfo),
png_get_next_frame_width(png_ptr, decoder->mInfo),
png_get_next_frame_height(png_ptr, decoder->mInfo));
nsresult rv =
decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
const bool isInterlaced = bool(decoder->interlacebuf);
nsresult rv = decoder->CreateFrame(decoder->format, frameRect, isInterlaced);
if (NS_FAILED(rv)) {
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
}

View File

@ -8,14 +8,9 @@
#define mozilla_image_decoders_nsPNGDecoder_h
#include "Decoder.h"
#include "gfxTypes.h"
#include "nsCOMPtr.h"
#include "png.h"
#include "qcms.h"
#include "SurfacePipe.h"
namespace mozilla {
namespace image {
@ -30,13 +25,33 @@ public:
virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override;
virtual Telemetry::ID SpeedHistogram() override;
nsresult CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
int32_t aWidth, int32_t aHeight,
gfx::SurfaceFormat aFormat);
private:
friend class DecoderFactory;
friend class nsICODecoder;
// Decoders should only be instantiated via DecoderFactory.
// XXX(seth): nsICODecoder is temporarily an exception to this rule.
explicit nsPNGDecoder(RasterImage* aImage);
nsresult CreateFrame(gfx::SurfaceFormat aFormat,
const gfx::IntRect& aFrameRect,
bool aIsInterlaced);
void EndImageFrame();
void CheckForTransparency(gfx::SurfaceFormat aFormat,
const gfx::IntRect& aFrameRect);
enum class TransparencyType
{
eNone,
eAlpha,
eFrameRect
};
TransparencyType GetTransparencyType(gfx::SurfaceFormat aFormat,
const gfx::IntRect& aFrameRect);
void PostHasTransparencyIfNeeded(TransparencyType aTransparencyType);
void PostInvalidationIfNeeded();
void WriteRow(uint8_t* aRow);
// Check if PNG is valid ICO (32bpp RGBA)
// http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
@ -69,17 +84,6 @@ public:
}
}
private:
friend class DecoderFactory;
friend class nsICODecoder;
// Decoders should only be instantiated via DecoderFactory.
// XXX(seth): nsICODecoder is temporarily an exception to this rule.
explicit nsPNGDecoder(RasterImage* aImage);
void PostPartialInvalidation(const IntRect& aInvalidRegion);
void PostFullInvalidation();
public:
png_structp mPNG;
png_infop mInfo;
@ -99,6 +103,7 @@ public:
uint32_t mCMSMode;
uint8_t mChannels;
uint8_t mPass;
bool mFrameIsHidden;
bool mDisablePremultipliedAlpha;
bool mSuccessfulEarlyFinish;
@ -117,6 +122,8 @@ public:
AnimFrameInfo mAnimInfo;
SurfacePipe mPipe; /// The SurfacePipe used to write to the output surface.
// The number of frames we've finished.
uint32_t mNumFrames;

View File

@ -16,13 +16,14 @@
#include "gfxAlphaRecovery.h"
#include "GeckoProfiler.h"
#include "mozilla/Likely.h"
#include "MainThreadUtils.h"
#include "mozilla/MemoryReporting.h"
#include "nsMargin.h"
#include "nsThreadUtils.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/gfx/Tools.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Telemetry.h"
#include "nsMargin.h"
#include "nsThreadUtils.h"
namespace mozilla {
@ -397,12 +398,19 @@ imgFrame::Optimize()
// moment
}
const bool usedSingleColorOptimizationUsefully = mSinglePixel &&
mFrameRect.Area() > 1;
Telemetry::Accumulate(Telemetry::IMAGE_OPTIMIZE_TO_SINGLE_COLOR_USED,
usedSingleColorOptimizationUsefully);
#ifdef ANDROID
SurfaceFormat optFormat = gfxPlatform::GetPlatform()
->Optimal2DFormatForContent(gfxContentType::COLOR);
if (mFormat != SurfaceFormat::B8G8R8A8 &&
optFormat == SurfaceFormat::R5G6B5_UINT16) {
Telemetry::Accumulate(Telemetry::IMAGE_OPTIMIZE_TO_565_USED, true);
RefPtr<VolatileBuffer> buf =
AllocateBufferForImage(mFrameRect.Size(), optFormat);
if (!buf) {
@ -638,7 +646,8 @@ void
imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
DisposalMethod aDisposalMethod /* = DisposalMethod::KEEP */,
int32_t aRawTimeout /* = 0 */,
BlendMethod aBlendMethod /* = BlendMethod::OVER */)
BlendMethod aBlendMethod /* = BlendMethod::OVER */,
const Maybe<IntRect>& aBlendRect /* = Nothing() */)
{
MonitorAutoLock lock(mMonitor);
MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
@ -650,6 +659,7 @@ imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */,
mDisposalMethod = aDisposalMethod;
mTimeout = aRawTimeout;
mBlendMethod = aBlendMethod;
mBlendRect = aBlendRect;
ImageUpdatedInternal(GetRect());
mFinished = true;
@ -925,7 +935,7 @@ imgFrame::GetAnimationData() const
bool hasAlpha = mFormat == SurfaceFormat::B8G8R8A8;
return AnimationData(data, PaletteDataLength(), mTimeout, GetRect(),
mBlendMethod, mDisposalMethod, hasAlpha);
mBlendMethod, mBlendRect, mDisposalMethod, hasAlpha);
}
void

View File

@ -7,6 +7,7 @@
#ifndef mozilla_image_imgFrame_h
#define mozilla_image_imgFrame_h
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Monitor.h"
#include "mozilla/Move.h"
@ -57,13 +58,14 @@ struct AnimationData
{
AnimationData(uint8_t* aRawData, uint32_t aPaletteDataLength,
int32_t aRawTimeout, const nsIntRect& aRect,
BlendMethod aBlendMethod, DisposalMethod aDisposalMethod,
bool aHasAlpha)
BlendMethod aBlendMethod, const Maybe<gfx::IntRect>& aBlendRect,
DisposalMethod aDisposalMethod, bool aHasAlpha)
: mRawData(aRawData)
, mPaletteDataLength(aPaletteDataLength)
, mRawTimeout(aRawTimeout)
, mRect(aRect)
, mBlendMethod(aBlendMethod)
, mBlendRect(aBlendRect)
, mDisposalMethod(aDisposalMethod)
, mHasAlpha(aHasAlpha)
{ }
@ -73,6 +75,7 @@ struct AnimationData
int32_t mRawTimeout;
nsIntRect mRect;
BlendMethod mBlendMethod;
Maybe<gfx::IntRect> mBlendRect;
DisposalMethod mDisposalMethod;
bool mHasAlpha;
};
@ -170,11 +173,15 @@ public:
* used; see FrameAnimator::GetTimeoutForFrame.
* @param aBlendMethod For animation frames, a blending method to be used
* when compositing this frame.
* @param aBlendRect For animation frames, if present, the subrect in
* which @aBlendMethod applies. Outside of this
* subrect, BlendMethod::OVER is always used.
*/
void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
int32_t aRawTimeout = 0,
BlendMethod aBlendMethod = BlendMethod::OVER);
BlendMethod aBlendMethod = BlendMethod::OVER,
const Maybe<IntRect>& aBlendRect = Nothing());
/**
* Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
@ -309,6 +316,7 @@ private: // data
DisposalMethod mDisposalMethod;
BlendMethod mBlendMethod;
Maybe<IntRect> mBlendRect;
SurfaceFormat mFormat;
bool mHasNoAlpha;

View File

@ -23,6 +23,7 @@ namespace image {
using namespace gfx;
using std::abs;
using std::vector;
///////////////////////////////////////////////////////////////////////////////
// General Helpers
@ -42,9 +43,21 @@ using std::abs;
return rv; \
}
#define ASSERT_GE_OR_RETURN(a, b, rv) \
EXPECT_GE(a, b); \
if (!((a) >= (b))) { \
return rv; \
}
#define ASSERT_LE_OR_RETURN(a, b, rv) \
EXPECT_LE(a, b); \
if (!((a) <= (b))) { \
if (!((a) <= (b))) { \
return rv; \
}
#define ASSERT_LT_OR_RETURN(a, b, rv) \
EXPECT_LT(a, b); \
if (!((a) < (b))) { \
return rv; \
}
@ -205,6 +218,41 @@ PalettedRectIsSolidColor(Decoder* aDecoder, const IntRect& aRect, uint8_t aColor
return true;
}
bool
RowHasPixels(SourceSurface* aSurface,
int32_t aRow,
const vector<BGRAColor>& aPixels)
{
ASSERT_GE_OR_RETURN(aRow, 0, false);
IntSize surfaceSize = aSurface->GetSize();
ASSERT_EQ_OR_RETURN(aPixels.size(), size_t(surfaceSize.width), false);
ASSERT_LT_OR_RETURN(aRow, surfaceSize.height, false);
RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
ASSERT_TRUE_OR_RETURN(dataSurface, false);
ASSERT_EQ_OR_RETURN(dataSurface->Stride(), surfaceSize.width * 4, false);
DataSourceSurface::ScopedMap mapping(dataSurface,
DataSourceSurface::MapType::READ);
ASSERT_TRUE_OR_RETURN(mapping.IsMapped(), false);
uint8_t* data = dataSurface->GetData();
ASSERT_TRUE_OR_RETURN(data != nullptr, false);
int32_t rowLength = dataSurface->Stride();
for (int32_t col = 0; col < surfaceSize.width; ++col) {
int32_t i = aRow * rowLength + col * 4;
ASSERT_EQ_OR_RETURN(aPixels[col].mBlue, data[i + 0], false);
ASSERT_EQ_OR_RETURN(aPixels[col].mGreen, data[i + 1], false);
ASSERT_EQ_OR_RETURN(aPixels[col].mRed, data[i + 2], false);
ASSERT_EQ_OR_RETURN(aPixels[col].mAlpha, data[i + 3], false);
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
// SurfacePipe Helpers

View File

@ -6,6 +6,8 @@
#ifndef mozilla_image_test_gtest_Common_h
#define mozilla_image_test_gtest_Common_h
#include <vector>
#include "gtest/gtest.h"
#include "mozilla/Maybe.h"
@ -70,6 +72,8 @@ struct ImageTestCase
struct BGRAColor
{
BGRAColor() : BGRAColor(0, 0, 0, 0) { }
BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha)
: mBlue(aBlue)
, mGreen(aGreen)
@ -79,6 +83,7 @@ struct BGRAColor
static BGRAColor Green() { return BGRAColor(0x00, 0xFF, 0x00, 0xFF); }
static BGRAColor Red() { return BGRAColor(0x00, 0x00, 0xFF, 0xFF); }
static BGRAColor Blue() { return BGRAColor(0xFF, 0x00, 0x00, 0xFF); }
static BGRAColor Transparent() { return BGRAColor(0x00, 0x00, 0x00, 0x00); }
uint32_t AsPixel() const { return gfxPackedPixel(mAlpha, mRed, mGreen, mBlue); }
@ -157,6 +162,14 @@ bool PalettedRectIsSolidColor(Decoder* aDecoder,
const gfx::IntRect& aRect,
uint8_t aColor);
/**
* @returns true if the pixels in @aRow of @aSurface match the pixels given in
* @aPixels.
*/
bool RowHasPixels(gfx::SourceSurface* aSurface,
int32_t aRow,
const std::vector<BGRAColor>& aPixels);
///////////////////////////////////////////////////////////////////////////////
// SurfacePipe Helpers

View File

@ -0,0 +1,671 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <algorithm>
#include <vector>
#include "gtest/gtest.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Maybe.h"
#include "Common.h"
#include "Decoder.h"
#include "DecoderFactory.h"
#include "SourceBuffer.h"
#include "SurfaceFilters.h"
#include "SurfacePipe.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::image;
using std::generate;
using std::vector;
template <typename Func> void
WithADAM7InterpolatingFilter(const IntSize& aSize, Func aFunc)
{
RefPtr<Decoder> decoder = CreateTrivialDecoder();
ASSERT_TRUE(bool(decoder));
WithFilterPipeline(decoder, Forward<Func>(aFunc),
ADAM7InterpolatingConfig { },
SurfaceConfig { decoder, 0, aSize,
SurfaceFormat::B8G8R8A8, false });
}
void
AssertConfiguringADAM7InterpolatingFilterFails(const IntSize& aSize)
{
RefPtr<Decoder> decoder = CreateTrivialDecoder();
ASSERT_TRUE(bool(decoder));
AssertConfiguringPipelineFails(decoder,
ADAM7InterpolatingConfig { },
SurfaceConfig { decoder, 0, aSize,
SurfaceFormat::B8G8R8A8, false });
}
uint8_t
InterpolateByte(uint8_t aByteA, uint8_t aByteB, float aWeight)
{
return uint8_t(aByteA * aWeight + aByteB * (1.0f - aWeight));
}
BGRAColor
InterpolateColors(BGRAColor aColor1, BGRAColor aColor2, float aWeight)
{
return BGRAColor(InterpolateByte(aColor1.mBlue, aColor2.mBlue, aWeight),
InterpolateByte(aColor1.mGreen, aColor2.mGreen, aWeight),
InterpolateByte(aColor1.mRed, aColor2.mRed, aWeight),
InterpolateByte(aColor1.mAlpha, aColor2.mAlpha, aWeight));
}
enum class ShouldInterpolate
{
eYes,
eNo
};
BGRAColor
HorizontallyInterpolatedPixel(uint32_t aCol,
uint32_t aWidth,
const vector<float>& aWeights,
ShouldInterpolate aShouldInterpolate,
const vector<BGRAColor>& aColors)
{
// We cycle through the vector of weights forever.
float weight = aWeights[aCol % aWeights.size()];
// Find the columns of the two final pixels for this set of weights.
uint32_t finalPixel1 = aCol - aCol % aWeights.size();
uint32_t finalPixel2 = finalPixel1 + aWeights.size();
// If |finalPixel2| is past the end of the row, that means that there is no
// final pixel after the pixel at |finalPixel1|. In that case, we just want to
// duplicate |finalPixel1|'s color until the end of the row. We can do that by
// setting |finalPixel2| equal to |finalPixel1| so that the interpolation has
// no effect.
if (finalPixel2 >= aWidth) {
finalPixel2 = finalPixel1;
}
// We cycle through the vector of colors forever (subject to the above
// constraint about the end of the row).
BGRAColor color1 = aColors[finalPixel1 % aColors.size()];
BGRAColor color2 = aColors[finalPixel2 % aColors.size()];
// If we're not interpolating, we treat all pixels which aren't final as
// transparent. Since the number of weights we have is equal to the stride
// between final pixels, we can check if |aCol| is a final pixel by checking
// whether |aCol| is a multiple of |aWeights.size()|.
if (aShouldInterpolate == ShouldInterpolate::eNo) {
return aCol % aWeights.size() == 0 ? color1
: BGRAColor::Transparent();
}
// Interpolate.
return InterpolateColors(color1, color2, weight);
}
vector<float>&
InterpolationWeights(int32_t aStride)
{
// Precalculated interpolation weights. These are used to interpolate
// between final pixels or between important rows. Although no interpolation
// is actually applied to the previous final pixel or important row value,
// the arrays still start with 1.0f, which is always skipped, primarily
// because otherwise |stride1Weights| would have zero elements.
static vector<float> stride8Weights =
{ 1.0f, 7 / 8.0f, 6 / 8.0f, 5 / 8.0f, 4 / 8.0f, 3 / 8.0f, 2 / 8.0f, 1 / 8.0f };
static vector<float> stride4Weights = { 1.0f, 3 / 4.0f, 2 / 4.0f, 1 / 4.0f };
static vector<float> stride2Weights = { 1.0f, 1 / 2.0f };
static vector<float> stride1Weights = { 1.0f };
switch (aStride) {
case 8: return stride8Weights;
case 4: return stride4Weights;
case 2: return stride2Weights;
case 1: return stride1Weights;
default:
MOZ_CRASH();
}
}
int32_t
ImportantRowStride(uint8_t aPass)
{
// The stride between important rows for each pass, with a dummy value for
// the nonexistent pass 0 and for pass 8, since the tests run an extra pass to
// make sure nothing breaks.
static int32_t strides[] = { 1, 8, 8, 4, 4, 2, 2, 1, 1 };
return strides[aPass];
}
size_t
FinalPixelStride(uint8_t aPass)
{
// The stride between the final pixels in important rows for each pass, with
// a dummy value for the nonexistent pass 0 and for pass 8, since the tests
// run an extra pass to make sure nothing breaks.
static size_t strides[] = { 1, 8, 4, 4, 2, 2, 1, 1, 1 };
return strides[aPass];
}
bool
IsImportantRow(int32_t aRow, uint8_t aPass)
{
return aRow % ImportantRowStride(aPass) == 0;
}
/**
* ADAM7 breaks up the image into 8x8 blocks. On each of the 7 passes, a new
* set of pixels in each block receives their final values, according to the
* following pattern:
*
* 1 6 4 6 2 6 4 6
* 7 7 7 7 7 7 7 7
* 5 6 5 6 5 6 5 6
* 7 7 7 7 7 7 7 7
* 3 6 4 6 3 6 4 6
* 7 7 7 7 7 7 7 7
* 5 6 5 6 5 6 5 6
* 7 7 7 7 7 7 7 7
*
* This function produces a row of pixels @aWidth wide, suitable for testing
* horizontal interpolation on pass @aPass. The pattern of pixels used is
* determined by @aPass and @aRow, which determine which pixels are final
* according to the table above, and @aColors, from which the pixel values
* are selected.
*
* There are two different behaviors: if |eNo| is passed for
* @aShouldInterpolate, non-final pixels are treated as transparent. If |eNo|
* is passed, non-final pixels get interpolated in from the surrounding final
* pixels. The intention is that |eNo| is passed to generate input which will
* be run through ADAM7InterpolatingFilter, and |eYes| is passed to generate
* reference data to check that the filter is performing horizontal
* interpolation correctly.
*
* This function does not perform vertical interpolation. Rows which aren't on
* the current pass are filled with transparent pixels.
*
* @return a vector<BGRAColor> representing a row of pixels.
*/
vector<BGRAColor>
ADAM7HorizontallyInterpolatedRow(uint8_t aPass,
uint32_t aRow,
uint32_t aWidth,
ShouldInterpolate aShouldInterpolate,
const vector<BGRAColor>& aColors)
{
EXPECT_GT(aPass, 0);
EXPECT_LE(aPass, 8);
EXPECT_GT(aColors.size(), 0u);
vector<BGRAColor> result(aWidth);
if (IsImportantRow(aRow, aPass)) {
vector<float>& weights = InterpolationWeights(FinalPixelStride(aPass));
// Compute the horizontally interpolated row.
uint32_t col = 0;
generate(result.begin(), result.end(), [&]{
return HorizontallyInterpolatedPixel(col++, aWidth, weights,
aShouldInterpolate, aColors);
});
} else {
// This is an unimportant row; just make the entire thing transparent.
generate(result.begin(), result.end(), []{
return BGRAColor::Transparent();
});
}
EXPECT_EQ(result.size(), size_t(aWidth));
return result;
}
WriteState
WriteUninterpolatedPixels(SurfaceFilter* aFilter,
const IntSize& aSize,
uint8_t aPass,
const vector<BGRAColor>& aColors)
{
WriteState result = WriteState::NEED_MORE_DATA;
for (int32_t row = 0; row < aSize.height; ++row) {
// Compute uninterpolated pixels for this row.
vector<BGRAColor> pixels =
Move(ADAM7HorizontallyInterpolatedRow(aPass, row, aSize.width,
ShouldInterpolate::eNo, aColors));
// Write them to the surface.
auto pixelIterator = pixels.cbegin();
result = aFilter->WritePixelsToRow<uint32_t>([&]{
return AsVariant((*pixelIterator++).AsPixel());
});
if (result != WriteState::NEED_MORE_DATA) {
break;
}
}
return result;
}
bool
CheckHorizontallyInterpolatedImage(Decoder* aDecoder,
const IntSize& aSize,
uint8_t aPass,
const vector<BGRAColor>& aColors)
{
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
RefPtr<SourceSurface> surface = currentFrame->GetSurface();
for (int32_t row = 0; row < aSize.height; ++row) {
if (!IsImportantRow(row, aPass)) {
continue; // Don't check rows which aren't important on this pass.
}
// Compute the expected pixels, *with* interpolation to match what the
// filter should have done.
vector<BGRAColor> expectedPixels =
Move(ADAM7HorizontallyInterpolatedRow(aPass, row, aSize.width,
ShouldInterpolate::eYes, aColors));
if (!RowHasPixels(surface, row, expectedPixels)) {
return false;
}
}
return true;
}
void
CheckHorizontalInterpolation(const IntSize& aSize,
const vector<BGRAColor>& aColors)
{
const IntRect surfaceRect(IntPoint(0, 0), aSize);
WithADAM7InterpolatingFilter(aSize,
[&](Decoder* aDecoder, SurfaceFilter* aFilter) {
// We check horizontal interpolation behavior for each pass individually. In
// addition to the normal 7 passes that ADAM7 includes, we also check an
// eighth pass to verify that nothing breaks if extra data is written.
for (uint8_t pass = 1; pass <= 8; ++pass) {
// Write our color pattern to the surface. We don't perform any
// interpolation when writing to the filter so that we can check that the
// filter itself *does*.
WriteState result =
WriteUninterpolatedPixels(aFilter, aSize, pass, aColors);
EXPECT_EQ(WriteState::FINISHED, result);
AssertCorrectPipelineFinalState(aFilter, surfaceRect, surfaceRect);
// Check that the generated image matches the expected pattern, with
// interpolation applied.
EXPECT_TRUE(CheckHorizontallyInterpolatedImage(aDecoder, aSize,
pass, aColors));
// Prepare for the next pass.
aFilter->ResetToFirstRow();
}
});
}
BGRAColor
ADAM7RowColor(int32_t aRow,
uint8_t aPass,
const vector<BGRAColor>& aColors)
{
EXPECT_LT(0, aPass);
EXPECT_GE(8, aPass);
EXPECT_LT(0u, aColors.size());
// If this is an important row, select the color from the provided vector of
// colors, which we cycle through infinitely. If not, just fill the row with
// transparent pixels.
return IsImportantRow(aRow, aPass) ? aColors[aRow % aColors.size()]
: BGRAColor::Transparent();
}
WriteState
WriteRowColorPixels(SurfaceFilter* aFilter,
const IntSize& aSize,
uint8_t aPass,
const vector<BGRAColor>& aColors)
{
WriteState result = WriteState::NEED_MORE_DATA;
for (int32_t row = 0; row < aSize.height; ++row) {
const uint32_t color = ADAM7RowColor(row, aPass, aColors).AsPixel();
// Fill the surface with |color| pixels.
result = aFilter->WritePixelsToRow<uint32_t>([&]{ return AsVariant(color); });
if (result != WriteState::NEED_MORE_DATA) {
break;
}
}
return result;
}
bool
CheckVerticallyInterpolatedImage(Decoder* aDecoder,
const IntSize& aSize,
uint8_t aPass,
const vector<BGRAColor>& aColors)
{
vector<float>& weights = InterpolationWeights(ImportantRowStride(aPass));
for (int32_t row = 0; row < aSize.height; ++row) {
// Vertically interpolation takes place between two important rows. The
// separation between the important rows is determined by the stride of this
// pass. When there is no "next" important row because we'd run off the
// bottom of the image, we use the same row for both. This matches
// ADAM7InterpolatingFilter's behavior of duplicating the last important row
// since there isn't another important row to vertically interpolate it
// with.
const int32_t stride = ImportantRowStride(aPass);
const int32_t prevImportantRow = row - row % stride;
const int32_t maybeNextImportantRow = prevImportantRow + stride;
const int32_t nextImportantRow = maybeNextImportantRow < aSize.height
? maybeNextImportantRow
: prevImportantRow;
// Retrieve the colors for the important rows we're going to interpolate.
const BGRAColor prevImportantRowColor =
ADAM7RowColor(prevImportantRow, aPass, aColors);
const BGRAColor nextImportantRowColor =
ADAM7RowColor(nextImportantRow, aPass, aColors);
// The weight we'll use for interpolation is also determined by the stride.
// A row halfway between two important rows should have pixels that have a
// 50% contribution from each of the important rows, for example.
const float weight = weights[row % stride];
const BGRAColor interpolatedColor =
InterpolateColors(prevImportantRowColor, nextImportantRowColor, weight);
// Generate a row of expected pixels. Every pixel in the row is always the
// same color since we're only testing vertical interpolation between
// solid-colored rows.
vector<BGRAColor> expectedPixels(aSize.width);
generate(expectedPixels.begin(), expectedPixels.end(), [&]{
return interpolatedColor;
});
// Check that the pixels match.
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
RefPtr<SourceSurface> surface = currentFrame->GetSurface();
if (!RowHasPixels(surface, row, expectedPixels)) {
return false;
}
}
return true;
}
void
CheckVerticalInterpolation(const IntSize& aSize,
const vector<BGRAColor>& aColors)
{
const IntRect surfaceRect(IntPoint(0, 0), aSize);
WithADAM7InterpolatingFilter(aSize,
[&](Decoder* aDecoder, SurfaceFilter* aFilter) {
for (uint8_t pass = 1; pass <= 8; ++pass) {
// Write a pattern of rows to the surface. Important rows will receive a
// color selected from |aColors|; unimportant rows will be transparent.
WriteState result = WriteRowColorPixels(aFilter, aSize, pass, aColors);
EXPECT_EQ(WriteState::FINISHED, result);
AssertCorrectPipelineFinalState(aFilter, surfaceRect, surfaceRect);
// Check that the generated image matches the expected pattern, with
// interpolation applied.
EXPECT_TRUE(CheckVerticallyInterpolatedImage(aDecoder, aSize,
pass, aColors));
// Prepare for the next pass.
aFilter->ResetToFirstRow();
}
});
}
void
CheckInterpolation(const IntSize& aSize, const vector<BGRAColor>& aColors)
{
CheckHorizontalInterpolation(aSize, aColors);
CheckVerticalInterpolation(aSize, aColors);
}
void
CheckADAM7InterpolatingWritePixels(const IntSize& aSize)
{
// This test writes 8 passes of green pixels (the seven ADAM7 passes, plus one
// extra to make sure nothing goes wrong if we write too much input) and verifies
// that the output is a solid green surface each time. Because all the pixels
// are the same color, interpolation doesn't matter; we test the correctness
// of the interpolation algorithm itself separately.
WithADAM7InterpolatingFilter(aSize,
[&](Decoder* aDecoder, SurfaceFilter* aFilter) {
IntRect rect(IntPoint(0, 0), aSize);
for (int32_t pass = 1; pass <= 8; ++pass) {
// We only actually write up to the last important row for each pass,
// because that row unambiguously determines the remaining rows.
const int32_t lastRow = aSize.height - 1;
const int32_t lastImportantRow =
lastRow - (lastRow % ImportantRowStride(pass));
const IntRect inputWriteRect(0, 0, aSize.width, lastImportantRow + 1);
CheckWritePixels(aDecoder, aFilter,
/* aOutputRect = */ Some(rect),
/* aInputRect = */ Some(rect),
/* aInputWriteRect = */ Some(inputWriteRect));
aFilter->ResetToFirstRow();
EXPECT_FALSE(aFilter->IsSurfaceFinished());
Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
EXPECT_TRUE(invalidRect.isNothing());
}
});
}
TEST(ImageADAM7InterpolatingFilter, WritePixels100_100)
{
CheckADAM7InterpolatingWritePixels(IntSize(100, 100));
}
TEST(ImageADAM7InterpolatingFilter, WritePixels99_99)
{
CheckADAM7InterpolatingWritePixels(IntSize(99, 99));
}
TEST(ImageADAM7InterpolatingFilter, WritePixels66_33)
{
CheckADAM7InterpolatingWritePixels(IntSize(66, 33));
}
TEST(ImageADAM7InterpolatingFilter, WritePixels33_66)
{
CheckADAM7InterpolatingWritePixels(IntSize(33, 66));
}
TEST(ImageADAM7InterpolatingFilter, WritePixels15_15)
{
CheckADAM7InterpolatingWritePixels(IntSize(15, 15));
}
TEST(ImageADAM7InterpolatingFilter, WritePixels9_9)
{
CheckADAM7InterpolatingWritePixels(IntSize(9, 9));
}
TEST(ImageADAM7InterpolatingFilter, WritePixels8_8)
{
CheckADAM7InterpolatingWritePixels(IntSize(8, 8));
}
TEST(ImageADAM7InterpolatingFilter, WritePixels7_7)
{
CheckADAM7InterpolatingWritePixels(IntSize(7, 7));
}
TEST(ImageADAM7InterpolatingFilter, WritePixels3_3)
{
CheckADAM7InterpolatingWritePixels(IntSize(3, 3));
}
TEST(ImageADAM7InterpolatingFilter, WritePixels1_1)
{
CheckADAM7InterpolatingWritePixels(IntSize(1, 1));
}
TEST(ImageADAM7InterpolatingFilter, TrivialInterpolation48_48)
{
CheckInterpolation(IntSize(48, 48), { BGRAColor::Green() });
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput33_17)
{
// We check interpolation using irregular patterns to make sure that the
// interpolation will look different for different passes.
CheckInterpolation(IntSize(33, 17), {
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput32_16)
{
CheckInterpolation(IntSize(32, 16), {
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput31_15)
{
CheckInterpolation(IntSize(31, 15), {
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput17_33)
{
CheckInterpolation(IntSize(17, 33), {
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput16_32)
{
CheckInterpolation(IntSize(16, 32), {
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput15_31)
{
CheckInterpolation(IntSize(15, 31), {
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput9_9)
{
CheckInterpolation(IntSize(9, 9), {
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput8_8)
{
CheckInterpolation(IntSize(8, 8), {
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput7_7)
{
CheckInterpolation(IntSize(7, 7), {
BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput3_3)
{
CheckInterpolation(IntSize(3, 3), {
BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Red()
});
}
TEST(ImageADAM7InterpolatingFilter, InterpolationOutput1_1)
{
CheckInterpolation(IntSize(1, 1), { BGRAColor::Blue() });
}
TEST(ImageADAM7InterpolatingFilter, ADAM7InterpolationFailsFor0_0)
{
// A 0x0 input size is invalid, so configuration should fail.
AssertConfiguringADAM7InterpolatingFilterFails(IntSize(0, 0));
}
TEST(ImageADAM7InterpolatingFilter, ADAM7InterpolationFailsForMinus1_Minus1)
{
// A negative input size is invalid, so configuration should fail.
AssertConfiguringADAM7InterpolatingFilterFails(IntSize(-1, -1));
}
TEST(ImageADAM7InterpolatingFilter, ConfiguringPalettedADAM7InterpolatingFilterFails)
{
RefPtr<Decoder> decoder = CreateTrivialDecoder();
ASSERT_TRUE(decoder != nullptr);
// ADAM7InterpolatingFilter does not support paletted images, so configuration
// should fail.
AssertConfiguringPipelineFails(decoder,
ADAM7InterpolatingConfig { },
PalettedSurfaceConfig { decoder, 0, IntSize(100, 100),
IntRect(0, 0, 50, 50),
SurfaceFormat::B8G8R8A8, 8,
false });
}

View File

@ -8,6 +8,7 @@ Library('imagetest')
UNIFIED_SOURCES = [
'Common.cpp',
'TestADAM7InterpolatingFilter.cpp',
'TestCopyOnWrite.cpp',
'TestDecoders.cpp',
'TestDecodeToSurface.cpp',

View File

@ -81,8 +81,21 @@ assertEq(Function.prototype[Symbol.hasInstance].call(doubleBound, instance), tru
assertEq(Function.prototype[Symbol.hasInstance].call(tripleBound, instance), true);
// Function.prototype[Symbol.hasInstance] is not configurable
let desc = Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance)
assertEq(desc.configurable, false)
let desc = Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance);
assertEq(desc.configurable, false);
// Attempting to use a non-callable @@hasInstance triggers a type error
// Bug 1280892
assertThrowsInstanceOf(() => {
var fun = function() {}
var p = new Proxy(fun, {
get(target, key) {
return /not-callable/;
}
});
fun instanceof p;
}, TypeError);
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -725,7 +725,7 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, MutableHandleValue v, bo
if (!hasInstance.isNullOrUndefined()) {
if (!IsCallable(hasInstance))
ReportIsNotFunction(cx, hasInstance);
return ReportIsNotFunction(cx, hasInstance);
/* Step 3. */
RootedValue rval(cx);
@ -738,8 +738,7 @@ js::InstanceOfOperator(JSContext* cx, HandleObject obj, MutableHandleValue v, bo
/* Step 4. */
if (!obj->isCallable()) {
RootedValue val(cx, ObjectValue(*obj));
ReportIsNotFunction(cx, val);
return false;
return ReportIsNotFunction(cx, val);
}
/* Step 5. */

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html style="transform: translateX(3px); display: grid;">
<head>
<!--
user_pref("layout.event-regions.enabled", true);
-->
</head>
<body>
<div style="position: absolute;">Z</div>
</body>
</html>

View File

@ -473,3 +473,4 @@ load 1234622-1.html
load 1235467-1.html
pref(dom.webcomponents.enabled,true) load 1261351.html
load 1270797-1.html
load 1278455-1.html

View File

@ -2496,14 +2496,14 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
// Make sure to start any background image loads for the root element now.
styleContext->StartBackgroundImageLoads();
nsFrameConstructorSaveState absoluteSaveState;
nsFrameConstructorSaveState docElementContainingBlockAbsoluteSaveState;
if (mHasRootAbsPosContainingBlock) {
// Push the absolute containing block now so we can absolutely position
// the root element
mDocElementContainingBlock->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
mDocElementContainingBlock,
absoluteSaveState);
docElementContainingBlockAbsoluteSaveState);
}
// The rules from CSS 2.1, section 9.2.4, have already been applied
@ -2520,6 +2520,8 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
nsIFrame* newFrame;
bool processChildren = false;
nsFrameConstructorSaveState absoluteSaveState;
// Check whether we need to build a XUL box or SVG root frame
#ifdef MOZ_XUL
if (aDocElement->IsXULElement()) {
@ -2565,12 +2567,26 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
contentFrame);
newFrame = contentFrame;
processChildren = true;
newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
if (display->IsAbsPosContainingBlock(newFrame)) {
state.PushAbsoluteContainingBlock(contentFrame, newFrame,
absoluteSaveState);
}
} else if (display->mDisplay == NS_STYLE_DISPLAY_GRID) {
contentFrame = NS_NewGridContainerFrame(mPresShell, styleContext);
InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock,
contentFrame);
newFrame = contentFrame;
processChildren = true;
newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
if (display->IsAbsPosContainingBlock(newFrame)) {
state.PushAbsoluteContainingBlock(contentFrame, newFrame,
absoluteSaveState);
}
} else if (display->mDisplay == NS_STYLE_DISPLAY_TABLE) {
// We're going to call the right function ourselves, so no need to give a
// function to this FrameConstructionData.

View File

@ -71,10 +71,12 @@ TryToStartImageLoadOnValue(const nsCSSValue& aValue, nsIDocument* aDocument,
if (aProperty == eCSSProperty_mask_image) {
nsIURI* docURI = aDocument->GetDocumentURI();
nsIURI* imageURI = aValue.GetURLValue();
bool isEqualExceptRef = false;
nsresult rv = imageURI->EqualsExceptRef(docURI, &isEqualExceptRef);
if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
return;
if (imageURI) {
bool isEqualExceptRef = false;
nsresult rv = imageURI->EqualsExceptRef(docURI, &isEqualExceptRef);
if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
return;
}
}
}
#endif

View File

@ -9,6 +9,12 @@
</head>
<body>
<div id="target-div">
<svg>
<rect id="svg-rect" width="100%" height="100%" fill="lime"/>
</svg>
</div>
<script>
"use strict";
@ -60,16 +66,10 @@ function waitForPaintFlushed() {
});
}
function addTestElement() {
var div = document.createElement("div");
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
div.appendChild(svg);
SimpleTest.waitForExplicitFinish();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("width", "100%");
rect.setAttribute("height", "100%");
rect.setAttribute("fill", "lime");
svg.appendChild(rect);
add_task(function* smil_is_in_display_none_subtree() {
yield waitForPaintFlushed();
var animate =
document.createElementNS("http://www.w3.org/2000/svg", "animate");
@ -78,21 +78,15 @@ function addTestElement() {
animate.setAttribute("values", "red;lime");
animate.setAttribute("dur", "1s");
animate.setAttribute("repeatCount", "indefinite");
rect.appendChild(animate);
document.getElementById("svg-rect").appendChild(animate);
document.body.appendChild(div);
return div;
}
SimpleTest.waitForExplicitFinish();
add_task(function* smil_is_in_display_none_subtree() {
var div = addTestElement();
yield waitForPaintFlushed();
var displayMarkers = yield observeStyling(5);
is(displayMarkers.length, 5, "should restyle in every frame");
var div = document.getElementById("target-div");
div.style.display = "none";
getComputedStyle(div).display;
var displayNoneMarkers = yield observeStyling(5);
@ -103,7 +97,7 @@ add_task(function* smil_is_in_display_none_subtree() {
var displayAgainMarkers = yield observeStyling(5);
is(displayAgainMarkers.length, 5, "should restyle again");
yield ensureElementRemoval(div);
yield ensureElementRemoval(animate);
});
</script>
</body>

View File

@ -5,13 +5,13 @@ This change comes from the blink repo https://codereview.appspot.com/229430043/
diff --git jdhuff.c jdhuff.c
--- jdhuff.c
+++ jdhuff.c
@@ -661,34 +661,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
@@ -664,17 +664,17 @@ decode_mcu_fast (j_decompress_ptr cinfo,
ASSIGN_STATE(state, entropy->saved);
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
JBLOCKROW block = MCU_data[blkn];
d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
d_derived_tbl *dctbl = entropy->dc_cur_tbls[blkn];
d_derived_tbl *actbl = entropy->ac_cur_tbls[blkn];
register int s, k, r, l;
- HUFF_DECODE_FAST(s, l, dctbl);
@ -24,12 +24,13 @@ diff --git jdhuff.c jdhuff.c
if (entropy->dc_needed[blkn]) {
int ci = cinfo->MCU_membership[blkn];
s += state.last_dc_val[ci];
@@ -682,17 +682,17 @@ decode_mcu_fast (j_decompress_ptr cinfo,
state.last_dc_val[ci] = s;
(*block)[0] = (JCOEF) s;
if (block)
(*block)[0] = (JCOEF) s;
}
if (entropy->ac_needed[blkn]) {
if (entropy->ac_needed[blkn] && block) {
for (k = 1; k < DCTSIZE2; k++) {
- HUFF_DECODE_FAST(s, l, actbl);
@ -42,7 +43,7 @@ diff --git jdhuff.c jdhuff.c
FILL_BIT_BUFFER_FAST
r = GET_BITS(s);
s = HUFF_EXTEND(r, s);
@@ -697,33 +697,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
@@ -701,33 +701,34 @@ decode_mcu_fast (j_decompress_ptr cinfo,
if (r != 15) break;
k += 15;
}
@ -81,7 +82,7 @@ diff --git jdhuff.c jdhuff.c
diff --git jdhuff.h jdhuff.h
--- jdhuff.h
+++ jdhuff.h
@@ -200,32 +200,34 @@ EXTERN(boolean) jpeg_fill_bit_buffer
@@ -203,32 +203,34 @@ EXTERN(boolean) jpeg_fill_bit_buffer
} else { \
slowlabel: \
if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
@ -116,5 +117,5 @@ diff --git jdhuff.h jdhuff.h
/* Out-of-line case for Huffman code fetching */
EXTERN(int) jpeg_huff_decode
(bitread_working_state * state, register bit_buf_type get_buffer,
register int bits_left, d_derived_tbl * htbl, int min_bits);
(bitread_working_state *state, register bit_buf_type get_buffer,
register int bits_left, d_derived_tbl *htbl, int min_bits);

88
media/libjpeg/LICENSE.md Normal file
View File

@ -0,0 +1,88 @@
libjpeg-turbo Licenses
======================
libjpeg-turbo is covered by three compatible BSD-style open source licenses:
- The IJG (Independent JPEG Group) License, which is listed in
[README.ijg](README.ijg)
This license applies to the libjpeg API library and associated programs
(any code inherited from libjpeg, and any modifications to that code.)
- The Modified (3-clause) BSD License, which is listed in
[turbojpeg.c](turbojpeg.c)
This license covers the TurboJPEG API library and associated programs.
- The zlib License, which is listed in [simd/jsimdext.inc](simd/jsimdext.inc)
This license is a subset of the other two, and it covers the libjpeg-turbo
SIMD extensions.
Complying with the libjpeg-turbo Licenses
=========================================
This section provides a roll-up of the libjpeg-turbo licensing terms, to the
best of our understanding.
1. If you are distributing a modified version of the libjpeg-turbo source,
then:
1. You cannot alter or remove any existing copyright or license notices
from the source.
**Origin**
- Clause 1 of the IJG License
- Clause 1 of the Modified BSD License
- Clauses 1 and 3 of the zlib License
2. You must add your own copyright notice to the header of each source
file you modified, so others can tell that you modified that file (if
there is not an existing copyright header in that file, then you can
simply add a notice stating that you modified the file.)
**Origin**
- Clause 1 of the IJG License
- Clause 2 of the zlib License
3. You must include the IJG README file, and you must not alter any of the
copyright or license text in that file.
**Origin**
- Clause 1 of the IJG License
2. If you are distributing only libjpeg-turbo binaries without the source, or
if you are distributing an application that statically links with
libjpeg-turbo, then:
1. Your product documentation must include a message stating:
This software is based in part on the work of the Independent JPEG
Group.
**Origin**
- Clause 2 of the IJG license
2. If your binary distribution includes or uses the TurboJPEG API, then
your product documentation must include the text of the Modified BSD
License.
**Origin**
- Clause 2 of the Modified BSD License
3. You cannot use the name of the IJG or The libjpeg-turbo Project or the
contributors thereof in advertising, publicity, etc.
**Origin**
- IJG License
- Clause 3 of the Modified BSD License
4. The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be
free of defects, nor do we accept any liability for undesirable
consequences resulting from your use of the software.
**Origin**
- IJG License
- Modified BSD License
- zlib License

View File

@ -24,13 +24,13 @@ To upgrade to a new revision of libjpeg-turbo, do the following:
You can easily look for all non *.c, *.h, *.asm, and *.inc files by running
$ hg status -nu | grep -v '\(c\|h\|asm\|inc\)$'
$ hg status -nu | grep -v '\(c\|h\|asm\|inc\|md\|ijg\)$'
Once you're comfortable that you're only deleting files you want to delete
(and you've hg add'ed the files you want to keep), you can nuke the remaining
files with
$ hg status -nu | grep -v '\(c\|h\|asm\|inc\)$' | xargs rm
$ hg status -nu | grep -v '\(c\|h\|asm\|inc\|md\|ijg\)$' | xargs rm
A helpful command for finding the *.c files which aren't *currently* part of
the build is
@ -48,6 +48,10 @@ To upgrade to a new revision of libjpeg-turbo, do the following:
$ hg addremove
== June 23, 2016 (libjpeg-turbo v1.5.0 3ff13e651bbe6de9c6f15d05235d1d4f26f63ffc 2016-05-31) ==
* Updated to v1.5.0 release.
== October 5, 2015 (libjpeg-turbo v1.4.2 d8da49effe6460d55239c4c009c57f42d8e4a494 2015-09-21) ==
* Updated to v1.4.2 release.

View File

@ -1,339 +0,0 @@
*******************************************************************************
** Background
*******************************************************************************
libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2,
NEON) to accelerate baseline JPEG compression and decompression on x86, x86-64,
and ARM systems. On such systems, libjpeg-turbo is generally 2-4x as fast as
libjpeg, all else being equal. On other types of systems, libjpeg-turbo can
still outperform libjpeg by a significant amount, by virtue of its
highly-optimized Huffman coding routines. In many cases, the performance of
libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
libjpeg-turbo implements both the traditional libjpeg API as well as the less
powerful but more straightforward TurboJPEG API. libjpeg-turbo also features
colorspace extensions that allow it to compress from/decompress to 32-bit and
big-endian pixel buffers (RGBX, XBGR, etc.), as well as a full-featured Java
interface.
libjpeg-turbo was originally based on libjpeg/SIMD, an MMX-accelerated
derivative of libjpeg v6b developed by Miyasaka Masaru. The TigerVNC and
VirtualGL projects made numerous enhancements to the codec in 2009, and in
early 2010, libjpeg-turbo spun off into an independent project, with the goal
of making high-speed JPEG compression/decompression technology available to a
broader range of users and developers.
*******************************************************************************
** License
*******************************************************************************
libjpeg-turbo is covered by three compatible BSD-style open source licenses.
Refer to LICENSE.txt for a roll-up of license terms.
*******************************************************************************
** Using libjpeg-turbo
*******************************************************************************
libjpeg-turbo includes two APIs that can be used to compress and decompress
JPEG images:
TurboJPEG API: This API provides an easy-to-use interface for compressing
and decompressing JPEG images in memory. It also provides some functionality
that would not be straightforward to achieve using the underlying libjpeg
API, such as generating planar YUV images and performing multiple
simultaneous lossless transforms on an image. The Java interface for
libjpeg-turbo is written on top of the TurboJPEG API.
libjpeg API: This is the de facto industry-standard API for compressing and
decompressing JPEG images. It is more difficult to use than the TurboJPEG
API but also more powerful. The libjpeg API implementation in libjpeg-turbo
is both API/ABI-compatible and mathematically compatible with libjpeg v6b.
It can also optionally be configured to be API/ABI-compatible with libjpeg v7
and v8 (see below.)
There is no significant performance advantage to either API when both are used
to perform similar operations.
=====================
Colorspace Extensions
=====================
libjpeg-turbo includes extensions that allow JPEG images to be compressed
directly from (and decompressed directly to) buffers that use BGR, BGRX,
RGBX, XBGR, and XRGB pixel ordering. This is implemented with ten new
colorspace constants:
JCS_EXT_RGB /* red/green/blue */
JCS_EXT_RGBX /* red/green/blue/x */
JCS_EXT_BGR /* blue/green/red */
JCS_EXT_BGRX /* blue/green/red/x */
JCS_EXT_XBGR /* x/blue/green/red */
JCS_EXT_XRGB /* x/red/green/blue */
JCS_EXT_RGBA /* red/green/blue/alpha */
JCS_EXT_BGRA /* blue/green/red/alpha */
JCS_EXT_ABGR /* alpha/blue/green/red */
JCS_EXT_ARGB /* alpha/red/green/blue */
Setting cinfo.in_color_space (compression) or cinfo.out_color_space
(decompression) to one of these values will cause libjpeg-turbo to read the
red, green, and blue values from (or write them to) the appropriate position in
the pixel when compressing from/decompressing to an RGB buffer.
Your application can check for the existence of these extensions at compile
time with:
#ifdef JCS_EXTENSIONS
At run time, attempting to use these extensions with a libjpeg implementation
that does not support them will result in a "Bogus input colorspace" error.
Applications can trap this error in order to test whether run-time support is
available for the colorspace extensions.
When using the RGBX, BGRX, XBGR, and XRGB colorspaces during decompression, the
X byte is undefined, and in order to ensure the best performance, libjpeg-turbo
can set that byte to whatever value it wishes. If an application expects the X
byte to be used as an alpha channel, then it should specify JCS_EXT_RGBA,
JCS_EXT_BGRA, JCS_EXT_ABGR, or JCS_EXT_ARGB. When these colorspace constants
are used, the X byte is guaranteed to be 0xFF, which is interpreted as opaque.
Your application can check for the existence of the alpha channel colorspace
extensions at compile time with:
#ifdef JCS_ALPHA_EXTENSIONS
jcstest.c, located in the libjpeg-turbo source tree, demonstrates how to check
for the existence of the colorspace extensions at compile time and run time.
===================================
libjpeg v7 and v8 API/ABI Emulation
===================================
With libjpeg v7 and v8, new features were added that necessitated extending the
compression and decompression structures. Unfortunately, due to the exposed
nature of those structures, extending them also necessitated breaking backward
ABI compatibility with previous libjpeg releases. Thus, programs that were
built to use libjpeg v7 or v8 did not work with libjpeg-turbo, since it is
based on the libjpeg v6b code base. Although libjpeg v7 and v8 are not
as widely used as v6b, enough programs (including a few Linux distros) made
the switch that there was a demand to emulate the libjpeg v7 and v8 ABIs
in libjpeg-turbo. It should be noted, however, that this feature was added
primarily so that applications that had already been compiled to use libjpeg
v7+ could take advantage of accelerated baseline JPEG encoding/decoding
without recompiling. libjpeg-turbo does not claim to support all of the
libjpeg v7+ features, nor to produce identical output to libjpeg v7+ in all
cases (see below.)
By passing an argument of --with-jpeg7 or --with-jpeg8 to configure, or an
argument of -DWITH_JPEG7=1 or -DWITH_JPEG8=1 to cmake, you can build a version
of libjpeg-turbo that emulates the libjpeg v7 or v8 ABI, so that programs
that are built against libjpeg v7 or v8 can be run with libjpeg-turbo. The
following section describes which libjpeg v7+ features are supported and which
aren't.
Support for libjpeg v7 and v8 Features:
---------------------------------------
Fully supported:
-- libjpeg: IDCT scaling extensions in decompressor
libjpeg-turbo supports IDCT scaling with scaling factors of 1/8, 1/4, 3/8,
1/2, 5/8, 3/4, 7/8, 9/8, 5/4, 11/8, 3/2, 13/8, 7/4, 15/8, and 2/1 (only 1/4
and 1/2 are SIMD-accelerated.)
-- libjpeg: arithmetic coding
-- libjpeg: In-memory source and destination managers
See notes below.
-- cjpeg: Separate quality settings for luminance and chrominance
Note that the libpjeg v7+ API was extended to accommodate this feature only
for convenience purposes. It has always been possible to implement this
feature with libjpeg v6b (see rdswitch.c for an example.)
-- cjpeg: 32-bit BMP support
-- cjpeg: -rgb option
-- jpegtran: lossless cropping
-- jpegtran: -perfect option
-- jpegtran: forcing width/height when performing lossless crop
-- rdjpgcom: -raw option
-- rdjpgcom: locale awareness
Not supported:
NOTE: As of this writing, extensive research has been conducted into the
usefulness of DCT scaling as a means of data reduction and SmartScale as a
means of quality improvement. The reader is invited to peruse the research at
http://www.libjpeg-turbo.org/About/SmartScale and draw his/her own conclusions,
but it is the general belief of our project that these features have not
demonstrated sufficient usefulness to justify inclusion in libjpeg-turbo.
-- libjpeg: DCT scaling in compressor
cinfo.scale_num and cinfo.scale_denom are silently ignored.
There is no technical reason why DCT scaling could not be supported when
emulating the libjpeg v7+ API/ABI, but without the SmartScale extension (see
below), only scaling factors of 1/2, 8/15, 4/7, 8/13, 2/3, 8/11, 4/5, and
8/9 would be available, which is of limited usefulness.
-- libjpeg: SmartScale
cinfo.block_size is silently ignored.
SmartScale is an extension to the JPEG format that allows for DCT block
sizes other than 8x8. Providing support for this new format would be
feasible (particularly without full acceleration.) However, until/unless
the format becomes either an official industry standard or, at minimum, an
accepted solution in the community, we are hesitant to implement it, as
there is no sense of whether or how it might change in the future. It is
our belief that SmartScale has not demonstrated sufficient usefulness as a
lossless format nor as a means of quality enhancement, and thus, our primary
interest in providing this feature would be as a means of supporting
additional DCT scaling factors.
-- libjpeg: Fancy downsampling in compressor
cinfo.do_fancy_downsampling is silently ignored.
This requires the DCT scaling feature, which is not supported.
-- jpegtran: Scaling
This requires both the DCT scaling and SmartScale features, which are not
supported.
-- Lossless RGB JPEG files
This requires the SmartScale feature, which is not supported.
What About libjpeg v9?
----------------------
libjpeg v9 introduced yet another field to the JPEG compression structure
(color_transform), thus making the ABI backward incompatible with that of
libjpeg v8. This new field was introduced solely for the purpose of supporting
lossless SmartScale encoding. Further, there was actually no reason to extend
the API in this manner, as the color transform could have just as easily been
activated by way of a new JPEG colorspace constant, thus preserving backward
ABI compatibility.
Our research (see link above) has shown that lossless SmartScale does not
generally accomplish anything that can't already be accomplished better with
existing, standard lossless formats. Thus, at this time, it is our belief that
there is not sufficient technical justification for software to upgrade from
libjpeg v8 to libjpeg v9, and therefore, not sufficient technical justification
for us to emulate the libjpeg v9 ABI.
=====================================
In-Memory Source/Destination Managers
=====================================
By default, libjpeg-turbo 1.3 and later includes the jpeg_mem_src() and
jpeg_mem_dest() functions, even when not emulating the libjpeg v8 API/ABI.
Previously, it was necessary to build libjpeg-turbo from source with libjpeg v8
API/ABI emulation in order to use the in-memory source/destination managers,
but several projects requested that those functions be included when emulating
the libjpeg v6b API/ABI as well. This allows the use of those functions by
programs that need them without breaking ABI compatibility for programs that
don't, and it allows those functions to be provided in the "official"
libjpeg-turbo binaries.
Those who are concerned about maintaining strict conformance with the libjpeg
v6b or v7 API can pass an argument of --without-mem-srcdst to configure or
an argument of -DWITH_MEM_SRCDST=0 to CMake prior to building libjpeg-turbo.
This will restore the pre-1.3 behavior, in which jpeg_mem_src() and
jpeg_mem_dest() are only included when emulating the libjpeg v8 API/ABI.
On Un*x systems, including the in-memory source/destination managers changes
the dynamic library version from 62.0.0 to 62.1.0 if using libjpeg v6b API/ABI
emulation and from 7.0.0 to 7.1.0 if using libjpeg v7 API/ABI emulation.
Note that, on most Un*x systems, the dynamic linker will not look for a
function in a library until that function is actually used. Thus, if a program
is built against libjpeg-turbo 1.3+ and uses jpeg_mem_src() or jpeg_mem_dest(),
that program will not fail if run against an older version of libjpeg-turbo or
against libjpeg v7- until the program actually tries to call jpeg_mem_src() or
jpeg_mem_dest(). Such is not the case on Windows. If a program is built
against the libjpeg-turbo 1.3+ DLL and uses jpeg_mem_src() or jpeg_mem_dest(),
then it must use the libjpeg-turbo 1.3+ DLL at run time.
Both cjpeg and djpeg have been extended to allow testing the in-memory
source/destination manager functions. See their respective man pages for more
details.
*******************************************************************************
** Mathematical Compatibility
*******************************************************************************
For the most part, libjpeg-turbo should produce identical output to libjpeg
v6b. The one exception to this is when using the floating point DCT/IDCT, in
which case the outputs of libjpeg v6b and libjpeg-turbo can differ for the
following reasons:
-- The SSE/SSE2 floating point DCT implementation in libjpeg-turbo is ever so
slightly more accurate than the implementation in libjpeg v6b, but not by
any amount perceptible to human vision (generally in the range of 0.01 to
0.08 dB gain in PNSR.)
-- When not using the SIMD extensions, libjpeg-turbo uses the more accurate
(and slightly faster) floating point IDCT algorithm introduced in libjpeg
v8a as opposed to the algorithm used in libjpeg v6b. It should be noted,
however, that this algorithm basically brings the accuracy of the floating
point IDCT in line with the accuracy of the slow integer IDCT. The floating
point DCT/IDCT algorithms are mainly a legacy feature, and they do not
produce significantly more accuracy than the slow integer algorithms (to put
numbers on this, the typical difference in PNSR between the two algorithms
is less than 0.10 dB, whereas changing the quality level by 1 in the upper
range of the quality scale is typically more like a 1.0 dB difference.)
-- If the floating point algorithms in libjpeg-turbo are not implemented using
SIMD instructions on a particular platform, then the accuracy of the
floating point DCT/IDCT can depend on the compiler settings.
While libjpeg-turbo does emulate the libjpeg v8 API/ABI, under the hood, it is
still using the same algorithms as libjpeg v6b, so there are several specific
cases in which libjpeg-turbo cannot be expected to produce the same output as
libjpeg v8:
-- When decompressing using scaling factors of 1/2 and 1/4, because libjpeg v8
implements those scaling algorithms differently than libjpeg v6b does, and
libjpeg-turbo's SIMD extensions are based on the libjpeg v6b behavior.
-- When using chrominance subsampling, because libjpeg v8 implements this
with its DCT/IDCT scaling algorithms rather than with a separate
downsampling/upsampling algorithm. In our testing, the subsampled/upsampled
output of libjpeg v8 is less accurate than that of libjpeg v6b for this
reason.
-- When decompressing using a scaling factor > 1 and merged (AKA "non-fancy" or
"non-smooth") chrominance upsampling, because libjpeg v8 does not support
merged upsampling with scaling factors > 1.
*******************************************************************************
** Performance Pitfalls
*******************************************************************************
===============
Restart Markers
===============
The optimized Huffman decoder in libjpeg-turbo does not handle restart markers
in a way that makes the rest of the libjpeg infrastructure happy, so it is
necessary to use the slow Huffman decoder when decompressing a JPEG image that
has restart markers. This can cause the decompression performance to drop by
as much as 20%, but the performance will still be much greater than that of
libjpeg. Many consumer packages, such as PhotoShop, use restart markers when
generating JPEG images, so images generated by those programs will experience
this issue.
===============================================
Fast Integer Forward DCT at High Quality Levels
===============================================
The algorithm used by the SIMD-accelerated quantization function cannot produce
correct results whenever the fast integer forward DCT is used along with a JPEG
quality of 98-100. Thus, libjpeg-turbo must use the non-SIMD quantization
function in those cases. This causes performance to drop by as much as 40%.
It is therefore strongly advised that you use the slow integer forward DCT
whenever encoding images with a JPEG quality of 98 or higher.

View File

@ -1,7 +1,7 @@
libjpeg-turbo note: This file has been modified by The libjpeg-turbo Project
to include only information relevant to libjpeg-turbo, to wordsmith certain
sections, and to remove impolitic language that existed in the libjpeg v8
README. It is included only for reference. Please see README-turbo.txt for
README. It is included only for reference. Please see README.md for
information specific to libjpeg-turbo.
@ -128,7 +128,7 @@ with respect to this software, its quality, accuracy, merchantability, or
fitness for a particular purpose. This software is provided "AS IS", and you,
its user, assume the entire risk as to its quality and accuracy.
This software is copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
This software is copyright (C) 1991-2016, Thomas G. Lane, Guido Vollbeding.
All Rights Reserved except as specified below.
Permission is hereby granted to use, copy, modify, and distribute this
@ -166,11 +166,11 @@ ltmain.sh). Another support script, install-sh, is copyright by X Consortium
but is also freely distributable.
The IJG distribution formerly included code to read and write GIF files.
To avoid entanglement with the Unisys LZW patent, GIF reading support has
been removed altogether, and the GIF writer has been simplified to produce
"uncompressed GIFs". This technique does not use the LZW algorithm; the
resulting GIF files are larger than usual, but are readable by all standard
GIF decoders.
To avoid entanglement with the Unisys LZW patent (now expired), GIF reading
support has been removed altogether, and the GIF writer has been simplified
to produce "uncompressed GIFs". This technique does not use the LZW
algorithm; the resulting GIF files are larger than usual, but are readable
by all standard GIF decoders.
We are required to state that
"The Graphics Interchange Format(c) is the Copyright property of
@ -189,8 +189,8 @@ The best short technical introduction to the JPEG compression algorithm is
Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
(Adjacent articles in that issue discuss MPEG motion picture compression,
applications of JPEG, and related topics.) If you don't have the CACM issue
handy, a PostScript file containing a revised version of Wallace's article is
available at http://www.ijg.org/files/wallace.ps.gz. The file (actually
handy, a PDF file containing a revised version of Wallace's article is
available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually
a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
omits the sample images that appeared in CACM, but it includes corrections
and some added material. Note: the Wallace article is copyright ACM and IEEE,
@ -246,9 +246,7 @@ ARCHIVE LOCATIONS
The "official" archive site for this software is www.ijg.org.
The most recent released version can always be found there in
directory "files". This particular version will be archived as
http://www.ijg.org/files/jpegsrc.v8d.tar.gz, and in Windows-compatible
"zip" archive format as http://www.ijg.org/files/jpegsr8d.zip.
directory "files".
The JPEG FAQ (Frequently Asked Questions) article is a source of some
general information about JPEG.

341
media/libjpeg/README.md Executable file
View File

@ -0,0 +1,341 @@
Background
==========
libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2,
NEON, AltiVec) to accelerate baseline JPEG compression and decompression on
x86, x86-64, ARM, and PowerPC systems. On such systems, libjpeg-turbo is
generally 2-6x as fast as libjpeg, all else being equal. On other types of
systems, libjpeg-turbo can still outperform libjpeg by a significant amount, by
virtue of its highly-optimized Huffman coding routines. In many cases, the
performance of libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
libjpeg-turbo implements both the traditional libjpeg API as well as the less
powerful but more straightforward TurboJPEG API. libjpeg-turbo also features
colorspace extensions that allow it to compress from/decompress to 32-bit and
big-endian pixel buffers (RGBX, XBGR, etc.), as well as a full-featured Java
interface.
libjpeg-turbo was originally based on libjpeg/SIMD, an MMX-accelerated
derivative of libjpeg v6b developed by Miyasaka Masaru. The TigerVNC and
VirtualGL projects made numerous enhancements to the codec in 2009, and in
early 2010, libjpeg-turbo spun off into an independent project, with the goal
of making high-speed JPEG compression/decompression technology available to a
broader range of users and developers.
License
=======
libjpeg-turbo is covered by three compatible BSD-style open source licenses.
Refer to [LICENSE.md](LICENSE.md) for a roll-up of license terms.
Building libjpeg-turbo
======================
Refer to [BUILDING.md](BUILDING.md) for complete instructions.
Using libjpeg-turbo
===================
libjpeg-turbo includes two APIs that can be used to compress and decompress
JPEG images:
- **TurboJPEG API**
This API provides an easy-to-use interface for compressing and decompressing
JPEG images in memory. It also provides some functionality that would not be
straightforward to achieve using the underlying libjpeg API, such as
generating planar YUV images and performing multiple simultaneous lossless
transforms on an image. The Java interface for libjpeg-turbo is written on
top of the TurboJPEG API.
- **libjpeg API**
This is the de facto industry-standard API for compressing and decompressing
JPEG images. It is more difficult to use than the TurboJPEG API but also
more powerful. The libjpeg API implementation in libjpeg-turbo is both
API/ABI-compatible and mathematically compatible with libjpeg v6b. It can
also optionally be configured to be API/ABI-compatible with libjpeg v7 and v8
(see below.)
There is no significant performance advantage to either API when both are used
to perform similar operations.
Colorspace Extensions
---------------------
libjpeg-turbo includes extensions that allow JPEG images to be compressed
directly from (and decompressed directly to) buffers that use BGR, BGRX,
RGBX, XBGR, and XRGB pixel ordering. This is implemented with ten new
colorspace constants:
JCS_EXT_RGB /* red/green/blue */
JCS_EXT_RGBX /* red/green/blue/x */
JCS_EXT_BGR /* blue/green/red */
JCS_EXT_BGRX /* blue/green/red/x */
JCS_EXT_XBGR /* x/blue/green/red */
JCS_EXT_XRGB /* x/red/green/blue */
JCS_EXT_RGBA /* red/green/blue/alpha */
JCS_EXT_BGRA /* blue/green/red/alpha */
JCS_EXT_ABGR /* alpha/blue/green/red */
JCS_EXT_ARGB /* alpha/red/green/blue */
Setting `cinfo.in_color_space` (compression) or `cinfo.out_color_space`
(decompression) to one of these values will cause libjpeg-turbo to read the
red, green, and blue values from (or write them to) the appropriate position in
the pixel when compressing from/decompressing to an RGB buffer.
Your application can check for the existence of these extensions at compile
time with:
#ifdef JCS_EXTENSIONS
At run time, attempting to use these extensions with a libjpeg implementation
that does not support them will result in a "Bogus input colorspace" error.
Applications can trap this error in order to test whether run-time support is
available for the colorspace extensions.
When using the RGBX, BGRX, XBGR, and XRGB colorspaces during decompression, the
X byte is undefined, and in order to ensure the best performance, libjpeg-turbo
can set that byte to whatever value it wishes. If an application expects the X
byte to be used as an alpha channel, then it should specify `JCS_EXT_RGBA`,
`JCS_EXT_BGRA`, `JCS_EXT_ABGR`, or `JCS_EXT_ARGB`. When these colorspace
constants are used, the X byte is guaranteed to be 0xFF, which is interpreted
as opaque.
Your application can check for the existence of the alpha channel colorspace
extensions at compile time with:
#ifdef JCS_ALPHA_EXTENSIONS
[jcstest.c](jcstest.c), located in the libjpeg-turbo source tree, demonstrates
how to check for the existence of the colorspace extensions at compile time and
run time.
libjpeg v7 and v8 API/ABI Emulation
-----------------------------------
With libjpeg v7 and v8, new features were added that necessitated extending the
compression and decompression structures. Unfortunately, due to the exposed
nature of those structures, extending them also necessitated breaking backward
ABI compatibility with previous libjpeg releases. Thus, programs that were
built to use libjpeg v7 or v8 did not work with libjpeg-turbo, since it is
based on the libjpeg v6b code base. Although libjpeg v7 and v8 are not
as widely used as v6b, enough programs (including a few Linux distros) made
the switch that there was a demand to emulate the libjpeg v7 and v8 ABIs
in libjpeg-turbo. It should be noted, however, that this feature was added
primarily so that applications that had already been compiled to use libjpeg
v7+ could take advantage of accelerated baseline JPEG encoding/decoding
without recompiling. libjpeg-turbo does not claim to support all of the
libjpeg v7+ features, nor to produce identical output to libjpeg v7+ in all
cases (see below.)
By passing an argument of `--with-jpeg7` or `--with-jpeg8` to `configure`, or
an argument of `-DWITH_JPEG7=1` or `-DWITH_JPEG8=1` to `cmake`, you can build a
version of libjpeg-turbo that emulates the libjpeg v7 or v8 ABI, so that
programs that are built against libjpeg v7 or v8 can be run with libjpeg-turbo.
The following section describes which libjpeg v7+ features are supported and
which aren't.
### Support for libjpeg v7 and v8 Features
#### Fully supported
- **libjpeg: IDCT scaling extensions in decompressor**
libjpeg-turbo supports IDCT scaling with scaling factors of 1/8, 1/4, 3/8,
1/2, 5/8, 3/4, 7/8, 9/8, 5/4, 11/8, 3/2, 13/8, 7/4, 15/8, and 2/1 (only 1/4
and 1/2 are SIMD-accelerated.)
- **libjpeg: Arithmetic coding**
- **libjpeg: In-memory source and destination managers**
See notes below.
- **cjpeg: Separate quality settings for luminance and chrominance**
Note that the libpjeg v7+ API was extended to accommodate this feature only
for convenience purposes. It has always been possible to implement this
feature with libjpeg v6b (see rdswitch.c for an example.)
- **cjpeg: 32-bit BMP support**
- **cjpeg: `-rgb` option**
- **jpegtran: Lossless cropping**
- **jpegtran: `-perfect` option**
- **jpegtran: Forcing width/height when performing lossless crop**
- **rdjpgcom: `-raw` option**
- **rdjpgcom: Locale awareness**
#### Not supported
NOTE: As of this writing, extensive research has been conducted into the
usefulness of DCT scaling as a means of data reduction and SmartScale as a
means of quality improvement. The reader is invited to peruse the research at
<http://www.libjpeg-turbo.org/About/SmartScale> and draw his/her own conclusions,
but it is the general belief of our project that these features have not
demonstrated sufficient usefulness to justify inclusion in libjpeg-turbo.
- **libjpeg: DCT scaling in compressor**
`cinfo.scale_num` and `cinfo.scale_denom` are silently ignored.
There is no technical reason why DCT scaling could not be supported when
emulating the libjpeg v7+ API/ABI, but without the SmartScale extension (see
below), only scaling factors of 1/2, 8/15, 4/7, 8/13, 2/3, 8/11, 4/5, and
8/9 would be available, which is of limited usefulness.
- **libjpeg: SmartScale**
`cinfo.block_size` is silently ignored.
SmartScale is an extension to the JPEG format that allows for DCT block
sizes other than 8x8. Providing support for this new format would be
feasible (particularly without full acceleration.) However, until/unless
the format becomes either an official industry standard or, at minimum, an
accepted solution in the community, we are hesitant to implement it, as
there is no sense of whether or how it might change in the future. It is
our belief that SmartScale has not demonstrated sufficient usefulness as a
lossless format nor as a means of quality enhancement, and thus our primary
interest in providing this feature would be as a means of supporting
additional DCT scaling factors.
- **libjpeg: Fancy downsampling in compressor**
`cinfo.do_fancy_downsampling` is silently ignored.
This requires the DCT scaling feature, which is not supported.
- **jpegtran: Scaling**
This requires both the DCT scaling and SmartScale features, which are not
supported.
- **Lossless RGB JPEG files**
This requires the SmartScale feature, which is not supported.
### What About libjpeg v9?
libjpeg v9 introduced yet another field to the JPEG compression structure
(`color_transform`), thus making the ABI backward incompatible with that of
libjpeg v8. This new field was introduced solely for the purpose of supporting
lossless SmartScale encoding. Furthermore, there was actually no reason to
extend the API in this manner, as the color transform could have just as easily
been activated by way of a new JPEG colorspace constant, thus preserving
backward ABI compatibility.
Our research (see link above) has shown that lossless SmartScale does not
generally accomplish anything that can't already be accomplished better with
existing, standard lossless formats. Therefore, at this time it is our belief
that there is not sufficient technical justification for software projects to
upgrade from libjpeg v8 to libjpeg v9, and thus there is not sufficient
echnical justification for us to emulate the libjpeg v9 ABI.
In-Memory Source/Destination Managers
-------------------------------------
By default, libjpeg-turbo 1.3 and later includes the `jpeg_mem_src()` and
`jpeg_mem_dest()` functions, even when not emulating the libjpeg v8 API/ABI.
Previously, it was necessary to build libjpeg-turbo from source with libjpeg v8
API/ABI emulation in order to use the in-memory source/destination managers,
but several projects requested that those functions be included when emulating
the libjpeg v6b API/ABI as well. This allows the use of those functions by
programs that need them, without breaking ABI compatibility for programs that
don't, and it allows those functions to be provided in the "official"
libjpeg-turbo binaries.
Those who are concerned about maintaining strict conformance with the libjpeg
v6b or v7 API can pass an argument of `--without-mem-srcdst` to `configure` or
an argument of `-DWITH_MEM_SRCDST=0` to `cmake` prior to building
libjpeg-turbo. This will restore the pre-1.3 behavior, in which
`jpeg_mem_src()` and `jpeg_mem_dest()` are only included when emulating the
libjpeg v8 API/ABI.
On Un*x systems, including the in-memory source/destination managers changes
the dynamic library version from 62.0.0 to 62.1.0 if using libjpeg v6b API/ABI
emulation and from 7.0.0 to 7.1.0 if using libjpeg v7 API/ABI emulation.
Note that, on most Un*x systems, the dynamic linker will not look for a
function in a library until that function is actually used. Thus, if a program
is built against libjpeg-turbo 1.3+ and uses `jpeg_mem_src()` or
`jpeg_mem_dest()`, that program will not fail if run against an older version
of libjpeg-turbo or against libjpeg v7- until the program actually tries to
call `jpeg_mem_src()` or `jpeg_mem_dest()`. Such is not the case on Windows.
If a program is built against the libjpeg-turbo 1.3+ DLL and uses
`jpeg_mem_src()` or `jpeg_mem_dest()`, then it must use the libjpeg-turbo 1.3+
DLL at run time.
Both cjpeg and djpeg have been extended to allow testing the in-memory
source/destination manager functions. See their respective man pages for more
details.
Mathematical Compatibility
==========================
For the most part, libjpeg-turbo should produce identical output to libjpeg
v6b. The one exception to this is when using the floating point DCT/IDCT, in
which case the outputs of libjpeg v6b and libjpeg-turbo can differ for the
following reasons:
- The SSE/SSE2 floating point DCT implementation in libjpeg-turbo is ever so
slightly more accurate than the implementation in libjpeg v6b, but not by
any amount perceptible to human vision (generally in the range of 0.01 to
0.08 dB gain in PNSR.)
- When not using the SIMD extensions, libjpeg-turbo uses the more accurate
(and slightly faster) floating point IDCT algorithm introduced in libjpeg
v8a as opposed to the algorithm used in libjpeg v6b. It should be noted,
however, that this algorithm basically brings the accuracy of the floating
point IDCT in line with the accuracy of the slow integer IDCT. The floating
point DCT/IDCT algorithms are mainly a legacy feature, and they do not
produce significantly more accuracy than the slow integer algorithms (to put
numbers on this, the typical difference in PNSR between the two algorithms
is less than 0.10 dB, whereas changing the quality level by 1 in the upper
range of the quality scale is typically more like a 1.0 dB difference.)
- If the floating point algorithms in libjpeg-turbo are not implemented using
SIMD instructions on a particular platform, then the accuracy of the
floating point DCT/IDCT can depend on the compiler settings.
While libjpeg-turbo does emulate the libjpeg v8 API/ABI, under the hood it is
still using the same algorithms as libjpeg v6b, so there are several specific
cases in which libjpeg-turbo cannot be expected to produce the same output as
libjpeg v8:
- When decompressing using scaling factors of 1/2 and 1/4, because libjpeg v8
implements those scaling algorithms differently than libjpeg v6b does, and
libjpeg-turbo's SIMD extensions are based on the libjpeg v6b behavior.
- When using chrominance subsampling, because libjpeg v8 implements this
with its DCT/IDCT scaling algorithms rather than with a separate
downsampling/upsampling algorithm. In our testing, the subsampled/upsampled
output of libjpeg v8 is less accurate than that of libjpeg v6b for this
reason.
- When decompressing using a scaling factor > 1 and merged (AKA "non-fancy" or
"non-smooth") chrominance upsampling, because libjpeg v8 does not support
merged upsampling with scaling factors > 1.
Performance Pitfalls
====================
Restart Markers
---------------
The optimized Huffman decoder in libjpeg-turbo does not handle restart markers
in a way that makes the rest of the libjpeg infrastructure happy, so it is
necessary to use the slow Huffman decoder when decompressing a JPEG image that
has restart markers. This can cause the decompression performance to drop by
as much as 20%, but the performance will still be much greater than that of
libjpeg. Many consumer packages, such as PhotoShop, use restart markers when
generating JPEG images, so images generated by those programs will experience
this issue.
Fast Integer Forward DCT at High Quality Levels
-----------------------------------------------
The algorithm used by the SIMD-accelerated quantization function cannot produce
correct results whenever the fast integer forward DCT is used along with a JPEG
quality of 98-100. Thus, libjpeg-turbo must use the non-SIMD quantization
function in those cases. This causes performance to drop by as much as 40%.
It is therefore strongly advised that you use the slow integer forward DCT
whenever encoding images with a JPEG quality of 98 or higher.

View File

@ -1,9 +1,12 @@
/*
* jaricom.c
*
* This file was part of the Independent JPEG Group's software:
* Developed 1997-2009 by Guido Vollbeding.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
* libjpeg-turbo Modifications:
* Copyright (C) 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains probability estimation tables for common use in
* arithmetic entropy encoding and decoding routines.
@ -18,7 +21,7 @@
#include "jpeglib.h"
/* The following #define specifies the packing of the four components
* into the compact INT32 representation.
* into the compact JLONG representation.
* Note that this formula must match the actual arithmetic encoder
* and decoder implementation. The implementation has to be changed
* if this formula is changed.
@ -26,9 +29,9 @@
* implementation (jbig_tab.c).
*/
#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b)
#define V(i,a,b,c,d) (((JLONG)a << 16) | ((JLONG)c << 8) | ((JLONG)d << 7) | b)
const INT32 jpeg_aritab[113+1] = {
const JLONG jpeg_aritab[113+1] = {
/*
* Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS
*/

View File

@ -6,7 +6,8 @@
* Modified 2003-2010 by Guido Vollbeding.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains application interface code for the compression half
* of the JPEG library. These are the "minimum" API routines that may be
@ -49,8 +50,8 @@ jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
* complain here.
*/
{
struct jpeg_error_mgr * err = cinfo->err;
void * client_data = cinfo->client_data; /* ignore Purify complaint here */
struct jpeg_error_mgr *err = cinfo->err;
void *client_data = cinfo->client_data; /* ignore Purify complaint here */
MEMZERO(cinfo, sizeof(struct jpeg_compress_struct));
cinfo->err = err;
cinfo->client_data = client_data;
@ -133,8 +134,8 @@ GLOBAL(void)
jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress)
{
int i;
JQUANT_TBL * qtbl;
JHUFF_TBL * htbl;
JQUANT_TBL *qtbl;
JHUFF_TBL *htbl;
for (i = 0; i < NUM_QUANT_TBLS; i++) {
if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL)

View File

@ -3,7 +3,8 @@
*
* Copyright (C) 1994-1996, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains application interface code for the compression half
* of the JPEG library. These are the "standard" API routines that are

View File

@ -3,9 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Developed 1997-2009 by Guido Vollbeding.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* libjpeg-turbo Modifications:
* Copyright (C) 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains portable arithmetic entropy encoding routines for JPEG
* (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
@ -25,10 +26,10 @@
typedef struct {
struct jpeg_entropy_encoder pub; /* public fields */
INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */
INT32 a; /* A register, normalized size of coding interval */
INT32 sc; /* counter for stacked 0xFF values which might overflow */
INT32 zc; /* counter for pending 0x00 output values which might *
JLONG c; /* C register, base of coding interval, layout as in sec. D.1.3 */
JLONG a; /* A register, normalized size of coding interval */
JLONG sc; /* counter for stacked 0xFF values which might overflow */
JLONG zc; /* counter for pending 0x00 output values which might *
* be discarded at the end ("Pacman" termination) */
int ct; /* bit shift counter, determines when next byte will be written */
int buffer; /* buffer for most recent output byte != 0xFF */
@ -40,14 +41,14 @@ typedef struct {
int next_restart_num; /* next restart number to write (0-7) */
/* Pointers to statistics areas (these workspaces have image lifespan) */
unsigned char * dc_stats[NUM_ARITH_TBLS];
unsigned char * ac_stats[NUM_ARITH_TBLS];
unsigned char *dc_stats[NUM_ARITH_TBLS];
unsigned char *ac_stats[NUM_ARITH_TBLS];
/* Statistics bin for coding with fixed probability 0.5 */
unsigned char fixed_bin[4];
} arith_entropy_encoder;
typedef arith_entropy_encoder * arith_entropy_ptr;
typedef arith_entropy_encoder *arith_entropy_ptr;
/* The following two definitions specify the allocation chunk size
* for the statistics area.
@ -97,8 +98,8 @@ typedef arith_entropy_encoder * arith_entropy_ptr;
#define CALCULATE_SPECTRAL_CONDITIONING
*/
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
* We assume that int right shift is unsigned if INT32 right shift is,
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than JLONG.
* We assume that int right shift is unsigned if JLONG right shift is,
* which should be safe.
*/
@ -118,7 +119,7 @@ LOCAL(void)
emit_byte (int val, j_compress_ptr cinfo)
/* Write next output byte; we do not support suspension in this module. */
{
struct jpeg_destination_mgr * dest = cinfo->dest;
struct jpeg_destination_mgr *dest = cinfo->dest;
*dest->next_output_byte++ = (JOCTET) val;
if (--dest->free_in_buffer == 0)
@ -135,7 +136,7 @@ METHODDEF(void)
finish_pass (j_compress_ptr cinfo)
{
arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
INT32 temp;
JLONG temp;
/* Section D.1.8: Termination of encoding */
@ -222,7 +223,7 @@ arith_encode (j_compress_ptr cinfo, unsigned char *st, int val)
{
register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
register unsigned char nl, nm;
register INT32 qe, temp;
register JLONG qe, temp;
register int sv;
/* Fetch values from our compact representation of Table D.2:
@ -322,7 +323,7 @@ emit_restart (j_compress_ptr cinfo, int restart_num)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
int ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
finish_pass(cinfo);
@ -682,7 +683,7 @@ METHODDEF(boolean)
encode_mcu (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
JBLOCKROW block;
unsigned char *st;
int blkn, ci, tbl, k, ke;
@ -825,7 +826,7 @@ start_pass (j_compress_ptr cinfo, boolean gather_statistics)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
int ci, tbl;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
if (gather_statistics)
/* Make sure to avoid that in the master control logic!

View File

@ -5,7 +5,8 @@
* Copyright (C) 1994-1997, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code and
* information relevant to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the coefficient buffer controller for compression.
* This controller is the top level of the JPEG compressor proper.
@ -53,7 +54,7 @@ typedef struct {
jvirt_barray_ptr whole_image[MAX_COMPONENTS];
} my_coef_controller;
typedef my_coef_controller * my_coef_ptr;
typedef my_coef_controller *my_coef_ptr;
/* Forward declarations */

View File

@ -4,8 +4,9 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2009-2012, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2009-2012, 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains input colorspace conversion routines.
*/
@ -34,7 +35,7 @@ rgb_ycc_convert_internal (j_compress_ptr cinfo,
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
register int r, g, b;
register INT32 * ctab = cconvert->rgb_ycc_tab;
register JLONG * ctab = cconvert->rgb_ycc_tab;
register JSAMPROW inptr;
register JSAMPROW outptr0, outptr1, outptr2;
register JDIMENSION col;
@ -91,7 +92,7 @@ rgb_gray_convert_internal (j_compress_ptr cinfo,
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
register int r, g, b;
register INT32 * ctab = cconvert->rgb_ycc_tab;
register JLONG * ctab = cconvert->rgb_ycc_tab;
register JSAMPROW inptr;
register JSAMPROW outptr;
register JDIMENSION col;

View File

@ -5,9 +5,10 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2009-2012, 2015 D. R. Commander.
* Copyright (C) 2014, MIPS Technologies, Inc., California
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2009-2012, 2015, D. R. Commander.
* Copyright (C) 2014, MIPS Technologies, Inc., California.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains input colorspace conversion routines.
*/
@ -25,10 +26,10 @@ typedef struct {
struct jpeg_color_converter pub; /* public fields */
/* Private state for RGB->YCC conversion */
INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
JLONG *rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
} my_color_converter;
typedef my_color_converter * my_cconvert_ptr;
typedef my_color_converter *my_cconvert_ptr;
/**************** RGB -> YCbCr conversion: most common case **************/
@ -62,9 +63,9 @@ typedef my_color_converter * my_cconvert_ptr;
*/
#define SCALEBITS 16 /* speediest right-shift on some machines */
#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS)
#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
#define CBCR_OFFSET ((JLONG) CENTERJSAMPLE << SCALEBITS)
#define ONE_HALF ((JLONG) 1 << (SCALEBITS-1))
#define FIX(x) ((JLONG) ((x) * (1L<<SCALEBITS) + 0.5))
/* We allocate one big table and divide it up into eight parts, instead of
* doing eight alloc_small requests. This lets us use a single table base
@ -197,13 +198,13 @@ METHODDEF(void)
rgb_ycc_start (j_compress_ptr cinfo)
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
INT32 * rgb_ycc_tab;
INT32 i;
JLONG *rgb_ycc_tab;
JLONG i;
/* Allocate and fill in the conversion tables. */
cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *)
cconvert->rgb_ycc_tab = rgb_ycc_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(TABLE_SIZE * sizeof(INT32)));
(TABLE_SIZE * sizeof(JLONG)));
for (i = 0; i <= MAXJSAMPLE; i++) {
rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i;
@ -381,7 +382,7 @@ cmyk_ycck_convert (j_compress_ptr cinfo,
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
register int r, g, b;
register INT32 * ctab = cconvert->rgb_ycc_tab;
register JLONG *ctab = cconvert->rgb_ycc_tab;
register JSAMPROW inptr;
register JSAMPROW outptr0, outptr1, outptr2, outptr3;
register JDIMENSION col;

View File

@ -6,8 +6,9 @@
* libjpeg-turbo Modifications:
* Copyright (C) 1999-2006, MIYASAKA Masaru.
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2011, 2014-2015 D. R. Commander
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2011, 2014-2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the forward-DCT management logic.
* This code selects a particular DCT implementation to be used,
@ -24,21 +25,21 @@
/* Private subobject for this module */
typedef void (*forward_DCT_method_ptr) (DCTELEM * data);
typedef void (*float_DCT_method_ptr) (FAST_FLOAT * data);
typedef void (*forward_DCT_method_ptr) (DCTELEM *data);
typedef void (*float_DCT_method_ptr) (FAST_FLOAT *data);
typedef void (*convsamp_method_ptr) (JSAMPARRAY sample_data,
JDIMENSION start_col,
DCTELEM * workspace);
DCTELEM *workspace);
typedef void (*float_convsamp_method_ptr) (JSAMPARRAY sample_data,
JDIMENSION start_col,
FAST_FLOAT *workspace);
typedef void (*quantize_method_ptr) (JCOEFPTR coef_block, DCTELEM * divisors,
DCTELEM * workspace);
typedef void (*quantize_method_ptr) (JCOEFPTR coef_block, DCTELEM *divisors,
DCTELEM *workspace);
typedef void (*float_quantize_method_ptr) (JCOEFPTR coef_block,
FAST_FLOAT * divisors,
FAST_FLOAT * workspace);
FAST_FLOAT *divisors,
FAST_FLOAT *workspace);
METHODDEF(void) quantize (JCOEFPTR, DCTELEM *, DCTELEM *);
@ -54,22 +55,22 @@ typedef struct {
* entries, because of scaling (especially for an unnormalized DCT).
* Each table is given in normal array order.
*/
DCTELEM * divisors[NUM_QUANT_TBLS];
DCTELEM *divisors[NUM_QUANT_TBLS];
/* work area for FDCT subroutine */
DCTELEM * workspace;
DCTELEM *workspace;
#ifdef DCT_FLOAT_SUPPORTED
/* Same as above for the floating-point case. */
float_DCT_method_ptr float_dct;
float_convsamp_method_ptr float_convsamp;
float_quantize_method_ptr float_quantize;
FAST_FLOAT * float_divisors[NUM_QUANT_TBLS];
FAST_FLOAT * float_workspace;
FAST_FLOAT *float_divisors[NUM_QUANT_TBLS];
FAST_FLOAT *float_workspace;
#endif
} my_fdct_controller;
typedef my_fdct_controller * my_fdct_ptr;
typedef my_fdct_controller *my_fdct_ptr;
#if BITS_IN_JSAMPLE == 8
@ -169,7 +170,7 @@ flss (UINT16 val)
*/
LOCAL(int)
compute_reciprocal (UINT16 divisor, DCTELEM * dtbl)
compute_reciprocal (UINT16 divisor, DCTELEM *dtbl)
{
UDCTELEM2 fq, fr;
UDCTELEM c;
@ -184,7 +185,7 @@ compute_reciprocal (UINT16 divisor, DCTELEM * dtbl)
dtbl[DCTSIZE2 * 0] = (DCTELEM) 1; /* reciprocal */
dtbl[DCTSIZE2 * 1] = (DCTELEM) 0; /* correction */
dtbl[DCTSIZE2 * 2] = (DCTELEM) 1; /* scale */
dtbl[DCTSIZE2 * 3] = (DCTELEM) (-sizeof(DCTELEM) * 8); /* shift */
dtbl[DCTSIZE2 * 3] = -(DCTELEM) (sizeof(DCTELEM) * 8); /* shift */
return 0;
}
@ -208,7 +209,11 @@ compute_reciprocal (UINT16 divisor, DCTELEM * dtbl)
dtbl[DCTSIZE2 * 0] = (DCTELEM) fq; /* reciprocal */
dtbl[DCTSIZE2 * 1] = (DCTELEM) c; /* correction + roundfactor */
#ifdef WITH_SIMD
dtbl[DCTSIZE2 * 2] = (DCTELEM) (1 << (sizeof(DCTELEM)*8*2 - r)); /* scale */
#else
dtbl[DCTSIZE2 * 2] = 1;
#endif
dtbl[DCTSIZE2 * 3] = (DCTELEM) r - sizeof(DCTELEM)*8; /* shift */
if(r <= 16) return 0;
@ -233,8 +238,8 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
int ci, qtblno, i;
jpeg_component_info *compptr;
JQUANT_TBL * qtbl;
DCTELEM * dtbl;
JQUANT_TBL *qtbl;
DCTELEM *dtbl;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@ -260,8 +265,8 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
dtbl = fdct->divisors[qtblno];
for (i = 0; i < DCTSIZE2; i++) {
#if BITS_IN_JSAMPLE == 8
if(!compute_reciprocal(qtbl->quantval[i] << 3, &dtbl[i])
&& fdct->quantize == jsimd_quantize)
if (!compute_reciprocal(qtbl->quantval[i] << 3, &dtbl[i]) &&
fdct->quantize == jsimd_quantize)
fdct->quantize = quantize;
#else
dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3;
@ -300,16 +305,16 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
dtbl = fdct->divisors[qtblno];
for (i = 0; i < DCTSIZE2; i++) {
#if BITS_IN_JSAMPLE == 8
if(!compute_reciprocal(
DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
(INT32) aanscales[i]),
CONST_BITS-3), &dtbl[i])
&& fdct->quantize == jsimd_quantize)
if (!compute_reciprocal(
DESCALE(MULTIPLY16V16((JLONG) qtbl->quantval[i],
(JLONG) aanscales[i]),
CONST_BITS-3), &dtbl[i]) &&
fdct->quantize == jsimd_quantize)
fdct->quantize = quantize;
#else
dtbl[i] = (DCTELEM)
DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
(INT32) aanscales[i]),
DESCALE(MULTIPLY16V16((JLONG) qtbl->quantval[i],
(JLONG) aanscales[i]),
CONST_BITS-3);
#endif
}
@ -327,7 +332,7 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
* What's actually stored is 1/divisor so that the inner loop can
* use a multiplication rather than a division.
*/
FAST_FLOAT * fdtbl;
FAST_FLOAT *fdtbl;
int row, col;
static const double aanscalefactor[DCTSIZE] = {
1.0, 1.387039845, 1.306562965, 1.175875602,
@ -365,7 +370,7 @@ start_pass_fdctmgr (j_compress_ptr cinfo)
*/
METHODDEF(void)
convsamp (JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM * workspace)
convsamp (JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM *workspace)
{
register DCTELEM *workspaceptr;
register JSAMPROW elemptr;
@ -400,7 +405,7 @@ convsamp (JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM * workspace)
*/
METHODDEF(void)
quantize (JCOEFPTR coef_block, DCTELEM * divisors, DCTELEM * workspace)
quantize (JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
{
int i;
DCTELEM temp;
@ -422,12 +427,12 @@ quantize (JCOEFPTR coef_block, DCTELEM * divisors, DCTELEM * workspace)
temp = -temp;
product = (UDCTELEM2)(temp + corr) * recip;
product >>= shift + sizeof(DCTELEM)*8;
temp = product;
temp = (DCTELEM)product;
temp = -temp;
} else {
product = (UDCTELEM2)(temp + corr) * recip;
product >>= shift + sizeof(DCTELEM)*8;
temp = product;
temp = (DCTELEM)product;
}
output_ptr[i] = (JCOEF) temp;
}
@ -482,7 +487,7 @@ quantize (JCOEFPTR coef_block, DCTELEM * divisors, DCTELEM * workspace)
*/
METHODDEF(void)
forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
forward_DCT (j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks)
@ -490,8 +495,8 @@ forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
{
/* This routine is heavily used, so it's worth coding it tightly. */
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no];
DCTELEM * workspace;
DCTELEM *divisors = fdct->divisors[compptr->quant_tbl_no];
DCTELEM *workspace;
JDIMENSION bi;
/* Make sure the compiler doesn't look up these every pass */
@ -519,7 +524,7 @@ forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
METHODDEF(void)
convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col, FAST_FLOAT * workspace)
convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col, FAST_FLOAT *workspace)
{
register FAST_FLOAT *workspaceptr;
register JSAMPROW elemptr;
@ -550,7 +555,7 @@ convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col, FAST_FLOAT * works
METHODDEF(void)
quantize_float (JCOEFPTR coef_block, FAST_FLOAT * divisors, FAST_FLOAT * workspace)
quantize_float (JCOEFPTR coef_block, FAST_FLOAT *divisors, FAST_FLOAT *workspace)
{
register FAST_FLOAT temp;
register int i;
@ -572,7 +577,7 @@ quantize_float (JCOEFPTR coef_block, FAST_FLOAT * divisors, FAST_FLOAT * workspa
METHODDEF(void)
forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks)
@ -580,8 +585,8 @@ forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
{
/* This routine is heavily used, so it's worth coding it tightly. */
my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no];
FAST_FLOAT * workspace;
FAST_FLOAT *divisors = fdct->float_divisors[compptr->quant_tbl_no];
FAST_FLOAT *workspace;
JDIMENSION bi;

View File

@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2009-2011, 2014-2015 D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2009-2011, 2014-2016, D. R. Commander.
* Copyright (C) 2015, Matthieu Darbois.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains Huffman entropy encoding routines.
*
@ -19,7 +21,8 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jchuff.h" /* Declarations shared with jcphuff.c */
#include "jsimd.h"
#include "jconfigint.h"
#include <limits.h>
/*
@ -99,23 +102,25 @@ typedef struct {
int next_restart_num; /* next restart number to write (0-7) */
/* Pointers to derived tables (these workspaces have image lifespan) */
c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
c_derived_tbl *dc_derived_tbls[NUM_HUFF_TBLS];
c_derived_tbl *ac_derived_tbls[NUM_HUFF_TBLS];
#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
long * dc_count_ptrs[NUM_HUFF_TBLS];
long * ac_count_ptrs[NUM_HUFF_TBLS];
long *dc_count_ptrs[NUM_HUFF_TBLS];
long *ac_count_ptrs[NUM_HUFF_TBLS];
#endif
int simd;
} huff_entropy_encoder;
typedef huff_entropy_encoder * huff_entropy_ptr;
typedef huff_entropy_encoder *huff_entropy_ptr;
/* Working state while writing an MCU.
* This struct contains all the fields that are needed by subroutines.
*/
typedef struct {
JOCTET * next_output_byte; /* => next byte to write in buffer */
JOCTET *next_output_byte; /* => next byte to write in buffer */
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
savable_state cur; /* Current bit buffer & DC state */
j_compress_ptr cinfo; /* dump_buffer needs access to this */
@ -143,7 +148,7 @@ start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int ci, dctbl, actbl;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
if (gather_statistics) {
#ifdef ENTROPY_OPT_SUPPORTED
@ -157,6 +162,8 @@ start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
entropy->pub.finish_pass = finish_pass_huff;
}
entropy->simd = jsimd_can_huff_encode_one_block();
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
dctbl = compptr->dc_tbl_no;
@ -213,7 +220,7 @@ start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
GLOBAL(void)
jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
c_derived_tbl ** pdtbl)
c_derived_tbl **pdtbl)
{
JHUFF_TBL *htbl;
c_derived_tbl *dtbl;
@ -268,7 +275,7 @@ jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
/* code is now 1 more than the last code used for codelength si; but
* it must still fit in si bits, since no code is allowed to be all ones.
*/
if (((INT32) code) >= (((INT32) 1) << si))
if (((JLONG) code) >= (((JLONG) 1) << si))
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
code <<= 1;
si++;
@ -311,10 +318,10 @@ jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
LOCAL(boolean)
dump_buffer (working_state * state)
dump_buffer (working_state *state)
/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
{
struct jpeg_destination_mgr * dest = state->cinfo->dest;
struct jpeg_destination_mgr *dest = state->cinfo->dest;
if (! (*dest->empty_output_buffer) (state->cinfo))
return FALSE;
@ -388,7 +395,7 @@ dump_buffer (working_state * state)
}
#define EMIT_CODE(code, size) { \
temp2 &= (((INT32) 1)<<nbits) - 1; \
temp2 &= (((JLONG) 1)<<nbits) - 1; \
CHECKBUF31() \
PUT_BITS(code, size) \
PUT_BITS(temp2, nbits) \
@ -402,7 +409,7 @@ dump_buffer (working_state * state)
}
#define EMIT_CODE(code, size) { \
temp2 &= (((INT32) 1)<<nbits) - 1; \
temp2 &= (((JLONG) 1)<<nbits) - 1; \
PUT_BITS(code, size) \
CHECKBUF15() \
PUT_BITS(temp2, nbits) \
@ -454,7 +461,7 @@ dump_buffer (working_state * state)
LOCAL(boolean)
flush_bits (working_state * state)
flush_bits (working_state *state)
{
JOCTET _buffer[BUFSIZE], *buffer;
size_t put_buffer; int put_bits;
@ -479,7 +486,24 @@ flush_bits (working_state * state)
/* Encode a single block's worth of coefficients */
LOCAL(boolean)
encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
encode_one_block_simd (working_state *state, JCOEFPTR block, int last_dc_val,
c_derived_tbl *dctbl, c_derived_tbl *actbl)
{
JOCTET _buffer[BUFSIZE], *buffer;
size_t bytes, bytestocopy; int localbuf = 0;
LOAD_BUFFER()
buffer = jsimd_huff_encode_one_block(state, buffer, block, last_dc_val,
dctbl, actbl);
STORE_BUFFER()
return TRUE;
}
LOCAL(boolean)
encode_one_block (working_state *state, JCOEFPTR block, int last_dc_val,
c_derived_tbl *dctbl, c_derived_tbl *actbl)
{
int temp, temp2, temp3;
@ -520,7 +544,7 @@ encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
EMIT_BITS(code, size)
/* Mask off any extra bits in code */
temp2 &= (((INT32) 1)<<nbits) - 1;
temp2 &= (((JLONG) 1)<<nbits) - 1;
/* Emit that number of bits of the value, if positive, */
/* or the complement of its magnitude, if negative. */
@ -592,7 +616,7 @@ encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
*/
LOCAL(boolean)
emit_restart (working_state * state, int restart_num)
emit_restart (working_state *state, int restart_num)
{
int ci;
@ -622,7 +646,7 @@ encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
working_state state;
int blkn, ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
/* Load up working state */
state.next_output_byte = cinfo->dest->next_output_byte;
@ -638,16 +662,30 @@ encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
}
/* Encode the MCU data blocks */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
if (! encode_one_block(&state,
MCU_data[blkn][0], state.cur.last_dc_val[ci],
entropy->dc_derived_tbls[compptr->dc_tbl_no],
entropy->ac_derived_tbls[compptr->ac_tbl_no]))
return FALSE;
/* Update last_dc_val */
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
if (entropy->simd) {
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
if (! encode_one_block_simd(&state,
MCU_data[blkn][0], state.cur.last_dc_val[ci],
entropy->dc_derived_tbls[compptr->dc_tbl_no],
entropy->ac_derived_tbls[compptr->ac_tbl_no]))
return FALSE;
/* Update last_dc_val */
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
}
} else {
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
if (! encode_one_block(&state,
MCU_data[blkn][0], state.cur.last_dc_val[ci],
entropy->dc_derived_tbls[compptr->dc_tbl_no],
entropy->ac_derived_tbls[compptr->ac_tbl_no]))
return FALSE;
/* Update last_dc_val */
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
}
}
/* Completed MCU, so update state */
@ -790,7 +828,7 @@ encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int blkn, ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
/* Take care of restart intervals if needed */
if (cinfo->restart_interval) {
@ -846,7 +884,7 @@ encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
*/
GLOBAL(void)
jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])
jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
{
#define MAX_CLEN 32 /* assumed maximum initial code length */
UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */
@ -991,7 +1029,7 @@ finish_pass_gather (j_compress_ptr cinfo)
{
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int ci, dctbl, actbl;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
JHUFF_TBL **htblptr;
boolean did_dc[NUM_HUFF_TBLS];
boolean did_ac[NUM_HUFF_TBLS];

View File

@ -5,7 +5,8 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains declarations for Huffman entropy encoding routines
* that are shared between the sequential encoder (jchuff.c) and the
@ -39,4 +40,4 @@ EXTERN(void) jpeg_make_c_derived_tbl
/* Generate an optimal table definition given the specified counts */
EXTERN(void) jpeg_gen_optimal_table
(j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[]);
(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[]);

View File

@ -3,7 +3,8 @@
*
* Copyright (C) 1991-1997, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains initialization logic for the JPEG compressor.
* This routine is in charge of selecting the modules to be executed and

View File

@ -5,7 +5,8 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the main buffer controller for compression.
* The main buffer lies between the pre-processor and the JPEG
@ -34,7 +35,7 @@ typedef struct {
JSAMPARRAY buffer[MAX_COMPONENTS];
} my_main_controller;
typedef my_main_controller * my_main_ptr;
typedef my_main_controller *my_main_ptr;
/* Forward declarations */

View File

@ -6,7 +6,8 @@
* Modified 2003-2010 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains routines to write JPEG datastream markers.
*/
@ -93,7 +94,7 @@ typedef struct {
unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */
} my_marker_writer;
typedef my_marker_writer * my_marker_ptr;
typedef my_marker_writer *my_marker_ptr;
/*
@ -112,7 +113,7 @@ LOCAL(void)
emit_byte (j_compress_ptr cinfo, int val)
/* Emit a byte */
{
struct jpeg_destination_mgr * dest = cinfo->dest;
struct jpeg_destination_mgr *dest = cinfo->dest;
*(dest->next_output_byte)++ = (JOCTET) val;
if (--dest->free_in_buffer == 0) {
@ -149,7 +150,7 @@ emit_dqt (j_compress_ptr cinfo, int index)
/* Emit a DQT marker */
/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
{
JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index];
JQUANT_TBL *qtbl = cinfo->quant_tbl_ptrs[index];
int prec;
int i;
@ -188,7 +189,7 @@ LOCAL(void)
emit_dht (j_compress_ptr cinfo, int index, boolean is_ac)
/* Emit a DHT marker */
{
JHUFF_TBL * htbl;
JHUFF_TBL *htbl;
int length, i;
if (is_ac) {

View File

@ -5,8 +5,9 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2003-2010 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2010, 2016, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains master control logic for the JPEG compressor.
* These routines are concerned with parameter validation, initial setup,
@ -18,6 +19,7 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jpegcomp.h"
#include "jconfigint.h"
/* Private state */
@ -37,9 +39,19 @@ typedef struct {
int total_passes; /* total # of passes needed */
int scan_number; /* current index in scan_info[] */
/*
* This is here so we can add libjpeg-turbo version/build information to the
* global string table without introducing a new global symbol. Adding this
* information to the global string table allows one to examine a binary
* object and determine which version of libjpeg-turbo it was built from or
* linked against.
*/
const char *jpeg_version;
} my_comp_master;
typedef my_comp_master * my_master_ptr;
typedef my_comp_master *my_master_ptr;
/*
@ -167,12 +179,12 @@ validate_script (j_compress_ptr cinfo)
* determine whether it uses progressive JPEG, and set cinfo->progressive_mode.
*/
{
const jpeg_scan_info * scanptr;
const jpeg_scan_info *scanptr;
int scanno, ncomps, ci, coefi, thisi;
int Ss, Se, Ah, Al;
boolean component_sent[MAX_COMPONENTS];
#ifdef C_PROGRESSIVE_SUPPORTED
int * last_bitpos_ptr;
int *last_bitpos_ptr;
int last_bitpos[MAX_COMPONENTS][DCTSIZE2];
/* -1 until that coefficient has been seen; then last Al for it */
#endif
@ -308,7 +320,7 @@ select_scan_parameters (j_compress_ptr cinfo)
if (cinfo->scan_info != NULL) {
/* Prepare for current scan --- the script is already validated */
my_master_ptr master = (my_master_ptr) cinfo->master;
const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number;
const jpeg_scan_info *scanptr = cinfo->scan_info + master->scan_number;
cinfo->comps_in_scan = scanptr->comps_in_scan;
for (ci = 0; ci < scanptr->comps_in_scan; ci++) {
@ -602,7 +614,7 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
cinfo->num_scans = 1;
}
if (cinfo->progressive_mode && !cinfo->arith_code) /* TEMPORARY HACK ??? */
if (cinfo->progressive_mode && !cinfo->arith_code) /* TEMPORARY HACK ??? */
cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */
/* Initialize my private state */
@ -622,4 +634,6 @@ jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
master->total_passes = cinfo->num_scans * 2;
else
master->total_passes = cinfo->num_scans;
master->jpeg_version = PACKAGE_NAME " version " VERSION " (build " BUILD ")";
}

View File

@ -2,10 +2,11 @@
* jcomapi.c
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.0
* Copyright (C) 1994-1997, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains application interface routines that are used for both
* compression and decompression.

View File

@ -6,7 +6,8 @@
* Modified 2003-2008 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2009-2011, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains optional default-setting code for the JPEG compressor.
* Applications do not have to use this file, but those that don't use it
@ -33,7 +34,7 @@ jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
* are limited to 1..255 for JPEG baseline compatibility.
*/
{
JQUANT_TBL ** qtblptr;
JQUANT_TBL **qtblptr;
int i;
long temp;
@ -321,7 +322,7 @@ jpeg_default_colorspace (j_compress_ptr cinfo)
GLOBAL(void)
jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
{
jpeg_component_info * compptr;
jpeg_component_info *compptr;
int ci;
#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \
@ -403,7 +404,7 @@ jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
#ifdef C_PROGRESSIVE_SUPPORTED
LOCAL(jpeg_scan_info *)
fill_a_scan (jpeg_scan_info * scanptr, int ci,
fill_a_scan (jpeg_scan_info *scanptr, int ci,
int Ss, int Se, int Ah, int Al)
/* Support routine: generate one scan for specified component */
{
@ -418,7 +419,7 @@ fill_a_scan (jpeg_scan_info * scanptr, int ci,
}
LOCAL(jpeg_scan_info *)
fill_scans (jpeg_scan_info * scanptr, int ncomps,
fill_scans (jpeg_scan_info *scanptr, int ncomps,
int Ss, int Se, int Ah, int Al)
/* Support routine: generate one scan for each component */
{
@ -437,7 +438,7 @@ fill_scans (jpeg_scan_info * scanptr, int ncomps,
}
LOCAL(jpeg_scan_info *)
fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)
fill_dc_scans (jpeg_scan_info *scanptr, int ncomps, int Ah, int Al)
/* Support routine: generate interleaved DC scan if possible, else N scans */
{
int ci;
@ -469,7 +470,7 @@ jpeg_simple_progression (j_compress_ptr cinfo)
{
int ncomps = cinfo->num_components;
int nscans;
jpeg_scan_info * scanptr;
jpeg_scan_info *scanptr;
/* Safety check to ensure start_compress not called yet. */
if (cinfo->global_state != CSTATE_START)

View File

@ -3,9 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1997, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* libjpeg-turbo Modifications:
* Copyright (C) 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains Huffman entropy encoding routines for progressive JPEG.
*
@ -32,9 +33,9 @@ typedef struct {
/* Bit-level coding status.
* next_output_byte/free_in_buffer are local copies of cinfo->dest fields.
*/
JOCTET * next_output_byte; /* => next byte to write in buffer */
JOCTET *next_output_byte; /* => next byte to write in buffer */
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
INT32 put_buffer; /* current bit-accumulation buffer */
size_t put_buffer; /* current bit-accumulation buffer */
int put_bits; /* # of bits now in it */
j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */
@ -45,7 +46,7 @@ typedef struct {
int ac_tbl_no; /* the table number of the single component */
unsigned int EOBRUN; /* run length of EOBs */
unsigned int BE; /* # of buffered correction bits before MCU */
char * bit_buffer; /* buffer for correction bits (1 per char) */
char *bit_buffer; /* buffer for correction bits (1 per char) */
/* packing correction bits tightly would save some space but cost time... */
unsigned int restarts_to_go; /* MCUs left in this restart interval */
@ -55,13 +56,13 @@ typedef struct {
* Since any one scan codes only DC or only AC, we only need one set
* of tables, not one for DC and one for AC.
*/
c_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
c_derived_tbl *derived_tbls[NUM_HUFF_TBLS];
/* Statistics tables for optimization; again, one set is enough */
long * count_ptrs[NUM_HUFF_TBLS];
long *count_ptrs[NUM_HUFF_TBLS];
} phuff_entropy_encoder;
typedef phuff_entropy_encoder * phuff_entropy_ptr;
typedef phuff_entropy_encoder *phuff_entropy_ptr;
/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit
* buffer can hold. Larger sizes may slightly improve compression, but
@ -71,8 +72,8 @@ typedef phuff_entropy_encoder * phuff_entropy_ptr;
#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
* We assume that int right shift is unsigned if INT32 right shift is,
/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than JLONG.
* We assume that int right shift is unsigned if JLONG right shift is,
* which should be safe.
*/
@ -110,7 +111,7 @@ start_pass_phuff (j_compress_ptr cinfo, boolean gather_statistics)
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
boolean is_DC_band;
int ci, tbl;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
entropy->cinfo = cinfo;
entropy->gather_statistics = gather_statistics;
@ -207,7 +208,7 @@ LOCAL(void)
dump_buffer (phuff_entropy_ptr entropy)
/* Empty the output buffer; we do not support suspension in this module. */
{
struct jpeg_destination_mgr * dest = entropy->cinfo->dest;
struct jpeg_destination_mgr *dest = entropy->cinfo->dest;
if (! (*dest->empty_output_buffer) (entropy->cinfo))
ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);
@ -230,7 +231,7 @@ emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size)
/* Emit some bits, unless we are in gather mode */
{
/* This routine is heavily used, so it's worth coding tightly. */
register INT32 put_buffer = (INT32) code;
register size_t put_buffer = (size_t) code;
register int put_bits = entropy->put_bits;
/* if size is 0, caller used an invalid Huffman table entry */
@ -240,7 +241,7 @@ emit_bits (phuff_entropy_ptr entropy, unsigned int code, int size)
if (entropy->gather_statistics)
return; /* do nothing if we're only getting stats */
put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
put_buffer &= (((size_t) 1)<<size) - 1; /* mask off any extra bits in code */
put_bits += size; /* new number of bits in buffer */
@ -283,7 +284,7 @@ emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol)
if (entropy->gather_statistics)
entropy->count_ptrs[tbl_no][symbol]++;
else {
c_derived_tbl * tbl = entropy->derived_tbls[tbl_no];
c_derived_tbl *tbl = entropy->derived_tbls[tbl_no];
emit_bits(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
}
}
@ -294,7 +295,7 @@ emit_symbol (phuff_entropy_ptr entropy, int tbl_no, int symbol)
*/
LOCAL(void)
emit_buffered_bits (phuff_entropy_ptr entropy, char * bufstart,
emit_buffered_bits (phuff_entropy_ptr entropy, char *bufstart,
unsigned int nbits)
{
if (entropy->gather_statistics)
@ -382,7 +383,7 @@ encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
int blkn, ci;
int Al = cinfo->Al;
JBLOCKROW block;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
ISHIFT_TEMPS
entropy->next_output_byte = cinfo->dest->next_output_byte;
@ -769,7 +770,7 @@ finish_pass_gather_phuff (j_compress_ptr cinfo)
phuff_entropy_ptr entropy = (phuff_entropy_ptr) cinfo->entropy;
boolean is_DC_band;
int ci, tbl;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
JHUFF_TBL **htblptr;
boolean did[NUM_HUFF_TBLS];

View File

@ -5,7 +5,8 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the compression preprocessing controller.
* This controller manages the color conversion, downsampling,
@ -69,7 +70,7 @@ typedef struct {
#endif
} my_prep_controller;
typedef my_prep_controller * my_prep_ptr;
typedef my_prep_controller *my_prep_ptr;
/*
@ -136,7 +137,7 @@ pre_process_data (j_compress_ptr cinfo,
my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
int numrows, ci;
JDIMENSION inrows;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
while (*in_row_ctr < in_rows_avail &&
*out_row_group_ctr < out_row_groups_avail) {
@ -271,7 +272,7 @@ create_context_buffer (j_compress_ptr cinfo)
my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
int rgroup_height = cinfo->max_v_samp_factor;
int ci, i;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
JSAMPARRAY true_buffer, fake_buffer;
/* Grab enough space for fake row pointers for all the components;
@ -318,7 +319,7 @@ jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
{
my_prep_ptr prep;
int ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
if (need_full_buffer) /* safety check */
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);

View File

@ -5,8 +5,10 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2014, MIPS Technologies, Inc., California
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2014, MIPS Technologies, Inc., California.
* Copyright (C) 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains downsampling routines.
*
@ -56,7 +58,7 @@
/* Pointer to routine to downsample a single component */
typedef void (*downsample1_ptr) (j_compress_ptr cinfo,
jpeg_component_info * compptr,
jpeg_component_info *compptr,
JSAMPARRAY input_data,
JSAMPARRAY output_data);
@ -69,7 +71,7 @@ typedef struct {
downsample1_ptr methods[MAX_COMPONENTS];
} my_downsampler;
typedef my_downsampler * my_downsample_ptr;
typedef my_downsampler *my_downsample_ptr;
/*
@ -122,7 +124,7 @@ sep_downsample (j_compress_ptr cinfo,
{
my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
int ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
JSAMPARRAY in_ptr, out_ptr;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
@ -142,14 +144,14 @@ sep_downsample (j_compress_ptr cinfo,
*/
METHODDEF(void)
int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
int_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
JSAMPROW inptr, outptr;
INT32 outvalue;
JLONG outvalue;
h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor;
v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor;
@ -172,7 +174,7 @@ int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
for (v = 0; v < v_expand; v++) {
inptr = input_data[inrow+v] + outcol_h;
for (h = 0; h < h_expand; h++) {
outvalue += (INT32) GETJSAMPLE(*inptr++);
outvalue += (JLONG) GETJSAMPLE(*inptr++);
}
}
*outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);
@ -189,7 +191,7 @@ int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
/* Copy the data */
@ -214,7 +216,7 @@ fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
int outrow;
@ -251,7 +253,7 @@ h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
int inrow, outrow;
@ -294,14 +296,14 @@ h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
int inrow, outrow;
JDIMENSION colctr;
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
INT32 membersum, neighsum, memberscale, neighscale;
JLONG membersum, neighsum, memberscale, neighscale;
/* Expand input data enough to let all the output samples be generated
* by the standard loop. Special-casing padded output would be more
@ -401,7 +403,7 @@ fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
JDIMENSION colctr;
JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
register JSAMPROW inptr, above_ptr, below_ptr, outptr;
INT32 membersum, neighsum, memberscale, neighscale;
JLONG membersum, neighsum, memberscale, neighscale;
int colsum, lastcolsum, nextcolsum;
/* Expand input data enough to let all the output samples be generated
@ -470,7 +472,7 @@ jinit_downsampler (j_compress_ptr cinfo)
{
my_downsample_ptr downsample;
int ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
boolean smoothok = TRUE;
downsample = (my_downsample_ptr)

View File

@ -6,7 +6,8 @@
* Modified 2000-2009 by Guido Vollbeding.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains library routines for transcoding compression,
* that is, writing raw DCT coefficient arrays to an output JPEG file.
@ -20,9 +21,9 @@
/* Forward declarations */
LOCAL(void) transencode_master_selection
(j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays);
(j_compress_ptr cinfo, jvirt_barray_ptr *coef_arrays);
LOCAL(void) transencode_coef_controller
(j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays);
(j_compress_ptr cinfo, jvirt_barray_ptr *coef_arrays);
/*
@ -38,7 +39,7 @@ LOCAL(void) transencode_coef_controller
*/
GLOBAL(void)
jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr *coef_arrays)
{
if (cinfo->global_state != CSTATE_START)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
@ -66,7 +67,7 @@ GLOBAL(void)
jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
j_compress_ptr dstinfo)
{
JQUANT_TBL ** qtblptr;
JQUANT_TBL **qtblptr;
jpeg_component_info *incomp, *outcomp;
JQUANT_TBL *c_quant, *slot_quant;
int tblno, ci, coefi;
@ -165,7 +166,7 @@ jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
LOCAL(void)
transencode_master_selection (j_compress_ptr cinfo,
jvirt_barray_ptr * coef_arrays)
jvirt_barray_ptr *coef_arrays)
{
/* Although we don't actually use input_components for transcoding,
* jcmaster.c's initial_setup will complain if input_components is 0.
@ -227,13 +228,13 @@ typedef struct {
int MCU_rows_per_iMCU_row; /* number of such rows needed */
/* Virtual block array for each component. */
jvirt_barray_ptr * whole_image;
jvirt_barray_ptr *whole_image;
/* Workspace for constructing dummy blocks at right/bottom edges. */
JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU];
} my_coef_controller;
typedef my_coef_controller * my_coef_ptr;
typedef my_coef_controller *my_coef_ptr;
LOCAL(void)
@ -374,7 +375,7 @@ compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
LOCAL(void)
transencode_coef_controller (j_compress_ptr cinfo,
jvirt_barray_ptr * coef_arrays)
jvirt_barray_ptr *coef_arrays)
{
my_coef_ptr coef;
JBLOCKROW buffer;

View File

@ -3,9 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* libjpeg-turbo Modifications:
* Copyright (C) 2016, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains application interface code for the decompression half
* of the JPEG library. These are the "minimum" API routines that may be
@ -21,6 +22,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jdmaster.h"
/*
@ -82,6 +84,14 @@ jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
/* OK, I'm ready */
cinfo->global_state = DSTATE_START;
/* The master struct is used to store extension parameters, so we allocate it
* here.
*/
cinfo->master = (struct jpeg_decomp_master *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(my_decomp_master));
MEMZERO(cinfo->master, sizeof(my_decomp_master));
}

View File

@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2010, 2015-2016, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains application interface code for the decompression half
* of the JPEG library. These are the "standard" API routines that are
@ -16,11 +18,11 @@
* whole decompression library into a transcoder.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jpegcomp.h"
#include "jdmainct.h"
#include "jdcoefct.h"
#include "jdsample.h"
#include "jmemsys.h"
/* Forward declarations */
LOCAL(boolean) output_pass_setup (j_decompress_ptr cinfo);
@ -138,6 +140,110 @@ output_pass_setup (j_decompress_ptr cinfo)
}
/*
* Enable partial scanline decompression
*
* Must be called after jpeg_start_decompress() and before any calls to
* jpeg_read_scanlines() or jpeg_skip_scanlines().
*
* Refer to libjpeg.txt for more information.
*/
GLOBAL(void)
jpeg_crop_scanline (j_decompress_ptr cinfo, JDIMENSION *xoffset,
JDIMENSION *width)
{
int ci, align, orig_downsampled_width;
JDIMENSION input_xoffset;
boolean reinit_upsampler = FALSE;
jpeg_component_info *compptr;
if (cinfo->global_state != DSTATE_SCANNING || cinfo->output_scanline != 0)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (!xoffset || !width)
ERREXIT(cinfo, JERR_BAD_CROP_SPEC);
/* xoffset and width must fall within the output image dimensions. */
if (*width == 0 || *xoffset + *width > cinfo->output_width)
ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
/* No need to do anything if the caller wants the entire width. */
if (*width == cinfo->output_width)
return;
/* Ensuring the proper alignment of xoffset is tricky. At minimum, it
* must align with an MCU boundary, because:
*
* (1) The IDCT is performed in blocks, and it is not feasible to modify
* the algorithm so that it can transform partial blocks.
* (2) Because of the SIMD extensions, any input buffer passed to the
* upsampling and color conversion routines must be aligned to the
* SIMD word size (for instance, 128-bit in the case of SSE2.) The
* easiest way to accomplish this without copying data is to ensure
* that upsampling and color conversion begin at the start of the
* first MCU column that will be inverse transformed.
*
* In practice, we actually impose a stricter alignment requirement. We
* require that xoffset be a multiple of the maximum MCU column width of all
* of the components (the "iMCU column width.") This is to simplify the
* single-pass decompression case, allowing us to use the same MCU column
* width for all of the components.
*/
align = cinfo->_min_DCT_scaled_size * cinfo->max_h_samp_factor;
/* Adjust xoffset to the nearest iMCU boundary <= the requested value */
input_xoffset = *xoffset;
*xoffset = (input_xoffset / align) * align;
/* Adjust the width so that the right edge of the output image is as
* requested (only the left edge is altered.) It is important that calling
* programs check this value after this function returns, so that they can
* allocate an output buffer with the appropriate size.
*/
*width = *width + input_xoffset - *xoffset;
cinfo->output_width = *width;
/* Set the first and last iMCU columns that we must decompress. These values
* will be used in single-scan decompressions.
*/
cinfo->master->first_iMCU_col =
(JDIMENSION) (long) (*xoffset) / (long) align;
cinfo->master->last_iMCU_col =
(JDIMENSION) jdiv_round_up((long) (*xoffset + cinfo->output_width),
(long) align) - 1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
/* Set downsampled_width to the new output width. */
orig_downsampled_width = compptr->downsampled_width;
compptr->downsampled_width =
(JDIMENSION) jdiv_round_up((long) (cinfo->output_width *
compptr->h_samp_factor),
(long) cinfo->max_h_samp_factor);
if (compptr->downsampled_width < 2 && orig_downsampled_width >= 2)
reinit_upsampler = TRUE;
/* Set the first and last iMCU columns that we must decompress. These
* values will be used in multi-scan decompressions.
*/
cinfo->master->first_MCU_col[ci] =
(JDIMENSION) (long) (*xoffset * compptr->h_samp_factor) /
(long) align;
cinfo->master->last_MCU_col[ci] =
(JDIMENSION) jdiv_round_up((long) ((*xoffset + cinfo->output_width) *
compptr->h_samp_factor),
(long) align) - 1;
}
if (reinit_upsampler) {
cinfo->master->jinit_upsampler_no_alloc = TRUE;
jinit_upsampler(cinfo);
cinfo->master->jinit_upsampler_no_alloc = FALSE;
}
}
/*
* Read some scanlines of data from the JPEG decompressor.
*
@ -179,6 +285,236 @@ jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
}
/* Dummy color convert function used by jpeg_skip_scanlines() */
LOCAL(void)
noop_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
{
}
/*
* In some cases, it is best to call jpeg_read_scanlines() and discard the
* output, rather than skipping the scanlines, because this allows us to
* maintain the internal state of the context-based upsampler. In these cases,
* we set up and tear down a dummy color converter in order to avoid valgrind
* errors and to achieve the best possible performance.
*/
LOCAL(void)
read_and_discard_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines)
{
JDIMENSION n;
void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION input_row, JSAMPARRAY output_buf,
int num_rows);
color_convert = cinfo->cconvert->color_convert;
cinfo->cconvert->color_convert = noop_convert;
for (n = 0; n < num_lines; n++)
jpeg_read_scanlines(cinfo, NULL, 1);
cinfo->cconvert->color_convert = color_convert;
}
/*
* Called by jpeg_skip_scanlines(). This partially skips a decompress block by
* incrementing the rowgroup counter.
*/
LOCAL(void)
increment_simple_rowgroup_ctr (j_decompress_ptr cinfo, JDIMENSION rows)
{
JDIMENSION rows_left;
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
/* Increment the counter to the next row group after the skipped rows. */
main_ptr->rowgroup_ctr += rows / cinfo->max_v_samp_factor;
/* Partially skipping a row group would involve modifying the internal state
* of the upsampler, so read the remaining rows into a dummy buffer instead.
*/
rows_left = rows % cinfo->max_v_samp_factor;
cinfo->output_scanline += rows - rows_left;
read_and_discard_scanlines(cinfo, rows_left);
}
/*
* Skips some scanlines of data from the JPEG decompressor.
*
* The return value will be the number of lines actually skipped. If skipping
* num_lines would move beyond the end of the image, then the actual number of
* lines remaining in the image is returned. Otherwise, the return value will
* be equal to num_lines.
*
* Refer to libjpeg.txt for more information.
*/
GLOBAL(JDIMENSION)
jpeg_skip_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines)
{
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
JDIMENSION i, x;
int y;
JDIMENSION lines_per_iMCU_row, lines_left_in_iMCU_row, lines_after_iMCU_row;
JDIMENSION lines_to_skip, lines_to_read;
if (cinfo->global_state != DSTATE_SCANNING)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
/* Do not skip past the bottom of the image. */
if (cinfo->output_scanline + num_lines >= cinfo->output_height) {
cinfo->output_scanline = cinfo->output_height;
return cinfo->output_height - cinfo->output_scanline;
}
if (num_lines == 0)
return 0;
lines_per_iMCU_row = cinfo->_min_DCT_scaled_size * cinfo->max_v_samp_factor;
lines_left_in_iMCU_row =
(lines_per_iMCU_row - (cinfo->output_scanline % lines_per_iMCU_row)) %
lines_per_iMCU_row;
lines_after_iMCU_row = num_lines - lines_left_in_iMCU_row;
/* Skip the lines remaining in the current iMCU row. When upsampling
* requires context rows, we need the previous and next rows in order to read
* the current row. This adds some complexity.
*/
if (cinfo->upsample->need_context_rows) {
/* If the skipped lines would not move us past the current iMCU row, we
* read the lines and ignore them. There might be a faster way of doing
* this, but we are facing increasing complexity for diminishing returns.
* The increasing complexity would be a by-product of meddling with the
* state machine used to skip context rows. Near the end of an iMCU row,
* the next iMCU row may have already been entropy-decoded. In this unique
* case, we will read the next iMCU row if we cannot skip past it as well.
*/
if ((num_lines < lines_left_in_iMCU_row + 1) ||
(lines_left_in_iMCU_row <= 1 && main_ptr->buffer_full &&
lines_after_iMCU_row < lines_per_iMCU_row + 1)) {
read_and_discard_scanlines(cinfo, num_lines);
return num_lines;
}
/* If the next iMCU row has already been entropy-decoded, make sure that
* we do not skip too far.
*/
if (lines_left_in_iMCU_row <= 1 && main_ptr->buffer_full) {
cinfo->output_scanline += lines_left_in_iMCU_row + lines_per_iMCU_row;
lines_after_iMCU_row -= lines_per_iMCU_row;
} else {
cinfo->output_scanline += lines_left_in_iMCU_row;
}
/* If we have just completed the first block, adjust the buffer pointers */
if (main_ptr->iMCU_row_ctr == 0 ||
(main_ptr->iMCU_row_ctr == 1 && lines_left_in_iMCU_row > 2))
set_wraparound_pointers(cinfo);
main_ptr->buffer_full = FALSE;
main_ptr->rowgroup_ctr = 0;
main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
upsample->next_row_out = cinfo->max_v_samp_factor;
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
}
/* Skipping is much simpler when context rows are not required. */
else {
if (num_lines < lines_left_in_iMCU_row) {
increment_simple_rowgroup_ctr(cinfo, num_lines);
return num_lines;
} else {
cinfo->output_scanline += lines_left_in_iMCU_row;
main_ptr->buffer_full = FALSE;
main_ptr->rowgroup_ctr = 0;
upsample->next_row_out = cinfo->max_v_samp_factor;
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
}
}
/* Calculate how many full iMCU rows we can skip. */
if (cinfo->upsample->need_context_rows)
lines_to_skip = ((lines_after_iMCU_row - 1) / lines_per_iMCU_row) *
lines_per_iMCU_row;
else
lines_to_skip = (lines_after_iMCU_row / lines_per_iMCU_row) *
lines_per_iMCU_row;
/* Calculate the number of lines that remain to be skipped after skipping all
* of the full iMCU rows that we can. We will not read these lines unless we
* have to.
*/
lines_to_read = lines_after_iMCU_row - lines_to_skip;
/* For images requiring multiple scans (progressive, non-interleaved, etc.),
* all of the entropy decoding occurs in jpeg_start_decompress(), assuming
* that the input data source is non-suspending. This makes skipping easy.
*/
if (cinfo->inputctl->has_multiple_scans) {
if (cinfo->upsample->need_context_rows) {
cinfo->output_scanline += lines_to_skip;
cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row;
main_ptr->iMCU_row_ctr += lines_after_iMCU_row / lines_per_iMCU_row;
/* It is complex to properly move to the middle of a context block, so
* read the remaining lines instead of skipping them.
*/
read_and_discard_scanlines(cinfo, lines_to_read);
} else {
cinfo->output_scanline += lines_to_skip;
cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row;
increment_simple_rowgroup_ctr(cinfo, lines_to_read);
}
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
return num_lines;
}
/* Skip the iMCU rows that we can safely skip. */
for (i = 0; i < lines_to_skip; i += lines_per_iMCU_row) {
for (y = 0; y < coef->MCU_rows_per_iMCU_row; y++) {
for (x = 0; x < cinfo->MCUs_per_row; x++) {
/* Calling decode_mcu() with a NULL pointer causes it to discard the
* decoded coefficients. This is ~5% faster for large subsets, but
* it's tough to tell a difference for smaller images.
*/
(*cinfo->entropy->decode_mcu) (cinfo, NULL);
}
}
cinfo->input_iMCU_row++;
cinfo->output_iMCU_row++;
if (cinfo->input_iMCU_row < cinfo->total_iMCU_rows)
start_iMCU_row(cinfo);
else
(*cinfo->inputctl->finish_input_pass) (cinfo);
}
cinfo->output_scanline += lines_to_skip;
if (cinfo->upsample->need_context_rows) {
/* Context-based upsampling keeps track of iMCU rows. */
main_ptr->iMCU_row_ctr += lines_to_skip / lines_per_iMCU_row;
/* It is complex to properly move to the middle of a context block, so
* read the remaining lines instead of skipping them.
*/
read_and_discard_scanlines(cinfo, lines_to_read);
} else {
increment_simple_rowgroup_ctr(cinfo, lines_to_read);
}
/* Since skipping lines involves skipping the upsampling step, the value of
* "rows_to_go" will become invalid unless we set it here. NOTE: This is a
* bit odd, since "rows_to_go" seems to be redundantly keeping track of
* output_scanline.
*/
upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
/* Always skip the requested number of lines. */
return num_lines;
}
/*
* Alternate entry point to read raw data.
* Processes exactly one iMCU row per call, unless suspended.

View File

@ -2,10 +2,11 @@
* jdarith.c
*
* This file was part of the Independent JPEG Group's software:
* Developed 1997-2009 by Guido Vollbeding.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* Developed 1997-2015 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains portable arithmetic entropy decoding routines for JPEG
* (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
@ -25,8 +26,8 @@
typedef struct {
struct jpeg_entropy_decoder pub; /* public fields */
INT32 c; /* C register, base of coding interval + input bit buffer */
INT32 a; /* A register, normalized size of coding interval */
JLONG c; /* C register, base of coding interval + input bit buffer */
JLONG a; /* A register, normalized size of coding interval */
int ct; /* bit shift counter, # of bits left in bit buffer part of C */
/* init: ct = -16 */
/* run: ct = 0..7 */
@ -37,14 +38,14 @@ typedef struct {
unsigned int restarts_to_go; /* MCUs left in this restart interval */
/* Pointers to statistics areas (these workspaces have image lifespan) */
unsigned char * dc_stats[NUM_ARITH_TBLS];
unsigned char * ac_stats[NUM_ARITH_TBLS];
unsigned char *dc_stats[NUM_ARITH_TBLS];
unsigned char *ac_stats[NUM_ARITH_TBLS];
/* Statistics bin for coding with fixed probability 0.5 */
unsigned char fixed_bin[4];
} arith_entropy_decoder;
typedef arith_entropy_decoder * arith_entropy_ptr;
typedef arith_entropy_decoder *arith_entropy_ptr;
/* The following two definitions specify the allocation chunk size
* for the statistics area.
@ -67,7 +68,7 @@ LOCAL(int)
get_byte (j_decompress_ptr cinfo)
/* Read next input byte; we do not support suspension in this module. */
{
struct jpeg_source_mgr * src = cinfo->src;
struct jpeg_source_mgr *src = cinfo->src;
if (src->bytes_in_buffer == 0)
if (! (*src->fill_input_buffer) (cinfo))
@ -96,7 +97,7 @@ get_byte (j_decompress_ptr cinfo)
* (instead of fixed) with the bit shift counter CT.
* Thus, we also need only one (variable instead of
* fixed size) shift for the LPS/MPS decision, and
* we can get away with any renormalization update
* we can do away with any renormalization update
* of C (except for new data insertion, of course).
*
* I've also introduced a new scheme for accessing
@ -109,7 +110,7 @@ arith_decode (j_decompress_ptr cinfo, unsigned char *st)
{
register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
register unsigned char nl, nm;
register INT32 qe, temp;
register JLONG qe, temp;
register int sv, data;
/* Renormalization & data input per section D.2.6 */
@ -193,7 +194,7 @@ process_restart (j_decompress_ptr cinfo)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
int ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
/* Advance past the RSTn marker */
if (! (*cinfo->marker->read_restart_marker) (cinfo))
@ -202,13 +203,13 @@ process_restart (j_decompress_ptr cinfo)
/* Re-initialize statistics areas */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
if (!cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
/* Reset DC predictions to 0 */
entropy->last_dc_val[ci] = 0;
entropy->dc_context[ci] = 0;
}
if (! cinfo->progressive_mode || cinfo->Ss) {
if (!cinfo->progressive_mode || cinfo->Ss) {
MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
}
}
@ -498,7 +499,7 @@ METHODDEF(boolean)
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
JBLOCKROW block;
unsigned char *st;
int blkn, ci, tbl, sign, k;
@ -516,7 +517,7 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
/* Outer loop handles each block in the MCU */
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
block = MCU_data[blkn];
block = MCU_data ? MCU_data[blkn] : NULL;
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
@ -563,7 +564,8 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
entropy->last_dc_val[ci] += v;
}
(*block)[0] = (JCOEF) entropy->last_dc_val[ci];
if (block)
(*block)[0] = (JCOEF) entropy->last_dc_val[ci];
/* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
@ -607,7 +609,8 @@ decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
while (m >>= 1)
if (arith_decode(cinfo, st)) v |= m;
v += 1; if (sign) v = -v;
(*block)[jpeg_natural_order[k]] = (JCOEF) v;
if (block)
(*block)[jpeg_natural_order[k]] = (JCOEF) v;
}
}
@ -624,7 +627,7 @@ start_pass (j_decompress_ptr cinfo)
{
arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
int ci, tbl;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
if (cinfo->progressive_mode) {
/* Validate progressive scan parameters */
@ -691,7 +694,7 @@ start_pass (j_decompress_ptr cinfo)
/* Allocate & initialize requested statistics areas */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
if (!cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
tbl = compptr->dc_tbl_no;
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
@ -703,7 +706,7 @@ start_pass (j_decompress_ptr cinfo)
entropy->last_dc_val[ci] = 0;
entropy->dc_context[ci] = 0;
}
if (! cinfo->progressive_mode || cinfo->Ss) {
if (!cinfo->progressive_mode || cinfo->Ss) {
tbl = compptr->ac_tbl_no;
if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);

View File

@ -5,8 +5,9 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* Modified 2009-2012 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2013, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2013, 2016, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains compression data destination routines for the case of
* emitting JPEG data to memory or to a file (or any stdio stream).
@ -23,7 +24,7 @@
#include "jerror.h"
#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
extern void * malloc (size_t size);
extern void *malloc (size_t size);
extern void free (void *ptr);
#endif
@ -33,11 +34,11 @@ extern void free (void *ptr);
typedef struct {
struct jpeg_destination_mgr pub; /* public fields */
FILE * outfile; /* target stream */
JOCTET * buffer; /* start of buffer */
FILE *outfile; /* target stream */
JOCTET *buffer; /* start of buffer */
} my_destination_mgr;
typedef my_destination_mgr * my_dest_ptr;
typedef my_destination_mgr *my_dest_ptr;
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
@ -48,14 +49,14 @@ typedef my_destination_mgr * my_dest_ptr;
typedef struct {
struct jpeg_destination_mgr pub; /* public fields */
unsigned char ** outbuffer; /* target buffer */
unsigned long * outsize;
unsigned char * newbuffer; /* newly allocated buffer */
JOCTET * buffer; /* start of buffer */
unsigned char **outbuffer; /* target buffer */
unsigned long *outsize;
unsigned char *newbuffer; /* newly allocated buffer */
JOCTET *buffer; /* start of buffer */
size_t bufsize;
} my_mem_destination_mgr;
typedef my_mem_destination_mgr * my_mem_dest_ptr;
typedef my_mem_destination_mgr *my_mem_dest_ptr;
#endif
@ -130,7 +131,7 @@ METHODDEF(boolean)
empty_mem_output_buffer (j_compress_ptr cinfo)
{
size_t nextsize;
JOCTET * nextbuffer;
JOCTET *nextbuffer;
my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
/* Try to allocate new buffer with double size */
@ -203,20 +204,25 @@ term_mem_destination (j_compress_ptr cinfo)
*/
GLOBAL(void)
jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
jpeg_stdio_dest (j_compress_ptr cinfo, FILE *outfile)
{
my_dest_ptr dest;
/* The destination object is made permanent so that multiple JPEG images
* can be written to the same file without re-executing jpeg_stdio_dest.
* This makes it dangerous to use this manager and a different destination
* manager serially with the same JPEG object, because their private object
* sizes may be different. Caveat programmer.
*/
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(my_destination_mgr));
} else if (cinfo->dest->init_destination != init_destination) {
/* It is unsafe to reuse the existing destination manager unless it was
* created by this function. Otherwise, there is no guarantee that the
* opaque structure is the right size. Note that we could just create a
* new structure, but the old structure would not be freed until
* jpeg_destroy_compress() was called.
*/
ERREXIT(cinfo, JERR_BUFFER_SIZE);
}
dest = (my_dest_ptr) cinfo->dest;
@ -237,11 +243,14 @@ jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
* larger memory, so the buffer is available to the application after
* finishing compression, and then the application is responsible for
* freeing the requested memory.
* Note: An initial buffer supplied by the caller is expected to be
* managed by the application. The library does not free such buffer
* when allocating a larger buffer.
*/
GLOBAL(void)
jpeg_mem_dest (j_compress_ptr cinfo,
unsigned char ** outbuffer, unsigned long * outsize)
unsigned char **outbuffer, unsigned long *outsize)
{
my_mem_dest_ptr dest;
@ -255,6 +264,11 @@ jpeg_mem_dest (j_compress_ptr cinfo,
cinfo->dest = (struct jpeg_destination_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(my_mem_destination_mgr));
} else if (cinfo->dest->init_destination != init_mem_destination) {
/* It is unsafe to reuse the existing destination manager unless it was
* created by this function.
*/
ERREXIT(cinfo, JERR_BUFFER_SIZE);
}
dest = (my_mem_dest_ptr) cinfo->dest;

View File

@ -5,8 +5,9 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* Modified 2009-2011 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2013, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2013, 2016, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains decompression data source routines for the case of
* reading JPEG data from memory or from a file (or any stdio stream).
@ -28,12 +29,12 @@
typedef struct {
struct jpeg_source_mgr pub; /* public fields */
FILE * infile; /* source stream */
JOCTET * buffer; /* start of buffer */
FILE *infile; /* source stream */
JOCTET *buffer; /* start of buffer */
boolean start_of_file; /* have we gotten any data yet? */
} my_source_mgr;
typedef my_source_mgr * my_src_ptr;
typedef my_source_mgr *my_src_ptr;
#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
@ -161,7 +162,7 @@ fill_mem_input_buffer (j_decompress_ptr cinfo)
METHODDEF(void)
skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
struct jpeg_source_mgr * src = cinfo->src;
struct jpeg_source_mgr *src = cinfo->src;
/* Just a dumb implementation for now. Could use fseek() except
* it doesn't work on pipes. Not clear that being smart is worth
@ -213,7 +214,7 @@ term_source (j_decompress_ptr cinfo)
*/
GLOBAL(void)
jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
jpeg_stdio_src (j_decompress_ptr cinfo, FILE *infile)
{
my_src_ptr src;
@ -221,8 +222,6 @@ jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
* of JPEG images can be read from the same file by calling jpeg_stdio_src
* only before the first one. (If we discarded the buffer at the end of
* one image, we'd likely lose the start of the next one.)
* This makes it unsafe to use this manager and a different source
* manager serially with the same JPEG object. Caveat programmer.
*/
if (cinfo->src == NULL) { /* first time for this JPEG object? */
cinfo->src = (struct jpeg_source_mgr *)
@ -232,6 +231,14 @@ jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
src->buffer = (JOCTET *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
INPUT_BUF_SIZE * sizeof(JOCTET));
} else if (cinfo->src->init_source != init_source) {
/* It is unsafe to reuse the existing source manager unless it was created
* by this function. Otherwise, there is no guarantee that the opaque
* structure is the right size. Note that we could just create a new
* structure, but the old structure would not be freed until
* jpeg_destroy_decompress() was called.
*/
ERREXIT(cinfo, JERR_BUFFER_SIZE);
}
src = (my_src_ptr) cinfo->src;
@ -254,9 +261,9 @@ jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
GLOBAL(void)
jpeg_mem_src (j_decompress_ptr cinfo,
unsigned char * inbuffer, unsigned long insize)
const unsigned char *inbuffer, unsigned long insize)
{
struct jpeg_source_mgr * src;
struct jpeg_source_mgr *src;
if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */
ERREXIT(cinfo, JERR_INPUT_EMPTY);
@ -269,6 +276,11 @@ jpeg_mem_src (j_decompress_ptr cinfo,
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(struct jpeg_source_mgr));
} else if (cinfo->src->init_source != init_mem_source) {
/* It is unsafe to reuse the existing source manager unless it was created
* by this function.
*/
ERREXIT(cinfo, JERR_BUFFER_SIZE);
}
src = cinfo->src;
@ -278,6 +290,6 @@ jpeg_mem_src (j_decompress_ptr cinfo,
src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->term_source = term_source;
src->bytes_in_buffer = (size_t) insize;
src->next_input_byte = (JOCTET *) inbuffer;
src->next_input_byte = (const JOCTET *) inbuffer;
}
#endif

View File

@ -4,8 +4,11 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2010, 2015-2016, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the coefficient buffer controller for decompression.
* This controller is the top level of the JPEG decompressor proper.
@ -16,53 +19,10 @@
* Also, the input side (only) is used when reading a file for transcoding.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jdcoefct.h"
#include "jpegcomp.h"
/* Block smoothing is only applicable for progressive JPEG, so: */
#ifndef D_PROGRESSIVE_SUPPORTED
#undef BLOCK_SMOOTHING_SUPPORTED
#endif
/* Private buffer controller object */
typedef struct {
struct jpeg_d_coef_controller pub; /* public fields */
/* These variables keep track of the current location of the input side. */
/* cinfo->input_iMCU_row is also used for this. */
JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
int MCU_vert_offset; /* counts MCU rows within iMCU row */
int MCU_rows_per_iMCU_row; /* number of such rows needed */
/* The output side's location is represented by cinfo->output_iMCU_row. */
/* In single-pass modes, it's sufficient to buffer just one MCU.
* We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
* and let the entropy decoder write into that workspace each time.
* In multi-pass modes, this array points to the current MCU's blocks
* within the virtual arrays; it is used only by the input side.
*/
JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
/* Temporary workspace for one MCU */
JCOEF * workspace;
#ifdef D_MULTISCAN_FILES_SUPPORTED
/* In multi-pass modes, we need a virtual block array for each component. */
jvirt_barray_ptr whole_image[MAX_COMPONENTS];
#endif
#ifdef BLOCK_SMOOTHING_SUPPORTED
/* When doing block smoothing, we latch coefficient Al values here */
int * coef_bits_latch;
#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
#endif
} my_coef_controller;
typedef my_coef_controller * my_coef_ptr;
/* Forward declarations */
METHODDEF(int) decompress_onepass
@ -78,30 +38,6 @@ METHODDEF(int) decompress_smooth_data
#endif
LOCAL(void)
start_iMCU_row (j_decompress_ptr cinfo)
/* Reset within-iMCU-row counters for a new row (input side) */
{
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
/* In an interleaved scan, an MCU row is the same as an iMCU row.
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
* But at the bottom of the image, process only what's left.
*/
if (cinfo->comps_in_scan > 1) {
coef->MCU_rows_per_iMCU_row = 1;
} else {
if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
else
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
}
coef->MCU_ctr = 0;
coef->MCU_vert_offset = 0;
}
/*
* Initialize for an input processing pass.
*/
@ -173,38 +109,46 @@ decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
coef->MCU_ctr = MCU_col_num;
return JPEG_SUSPENDED;
}
/* Determine where data should go in output_buf and do the IDCT thing.
* We skip dummy blocks at the right and bottom edges (but blkn gets
* incremented past them!). Note the inner loop relies on having
* allocated the MCU_buffer[] blocks sequentially.
/* Only perform the IDCT on blocks that are contained within the desired
* cropping region.
*/
blkn = 0; /* index of current DCT block within MCU */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* Don't bother to IDCT an uninteresting component. */
if (! compptr->component_needed) {
blkn += compptr->MCU_blocks;
continue;
}
inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
: compptr->last_col_width;
output_ptr = output_buf[compptr->component_index] +
yoffset * compptr->_DCT_scaled_size;
start_col = MCU_col_num * compptr->MCU_sample_width;
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (cinfo->input_iMCU_row < last_iMCU_row ||
yoffset+yindex < compptr->last_row_height) {
output_col = start_col;
for (xindex = 0; xindex < useful_width; xindex++) {
(*inverse_DCT) (cinfo, compptr,
(JCOEFPTR) coef->MCU_buffer[blkn+xindex],
output_ptr, output_col);
output_col += compptr->_DCT_scaled_size;
}
if (MCU_col_num >= cinfo->master->first_iMCU_col &&
MCU_col_num <= cinfo->master->last_iMCU_col) {
/* Determine where data should go in output_buf and do the IDCT thing.
* We skip dummy blocks at the right and bottom edges (but blkn gets
* incremented past them!). Note the inner loop relies on having
* allocated the MCU_buffer[] blocks sequentially.
*/
blkn = 0; /* index of current DCT block within MCU */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* Don't bother to IDCT an uninteresting component. */
if (! compptr->component_needed) {
blkn += compptr->MCU_blocks;
continue;
}
inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
: compptr->last_col_width;
output_ptr = output_buf[compptr->component_index] +
yoffset * compptr->_DCT_scaled_size;
start_col = (MCU_col_num - cinfo->master->first_iMCU_col) *
compptr->MCU_sample_width;
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (cinfo->input_iMCU_row < last_iMCU_row ||
yoffset+yindex < compptr->last_row_height) {
output_col = start_col;
for (xindex = 0; xindex < useful_width; xindex++) {
(*inverse_DCT) (cinfo, compptr,
(JCOEFPTR) coef->MCU_buffer[blkn+xindex],
output_ptr, output_col);
output_col += compptr->_DCT_scaled_size;
}
}
blkn += compptr->MCU_width;
output_ptr += compptr->_DCT_scaled_size;
}
blkn += compptr->MCU_width;
output_ptr += compptr->_DCT_scaled_size;
}
}
}
@ -359,9 +303,10 @@ decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */
for (block_row = 0; block_row < block_rows; block_row++) {
buffer_ptr = buffer[block_row];
buffer_ptr = buffer[block_row] + cinfo->master->first_MCU_col[ci];
output_col = 0;
for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
for (block_num = cinfo->master->first_MCU_col[ci];
block_num <= cinfo->master->last_MCU_col[ci]; block_num++) {
(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
output_ptr, output_col);
buffer_ptr++;
@ -411,9 +356,9 @@ smoothing_ok (j_decompress_ptr cinfo)
boolean smoothing_useful = FALSE;
int ci, coefi;
jpeg_component_info *compptr;
JQUANT_TBL * qtable;
int * coef_bits;
int * coef_bits_latch;
JQUANT_TBL *qtable;
int *coef_bits;
int *coef_bits_latch;
if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
return FALSE;
@ -474,10 +419,10 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
jpeg_component_info *compptr;
inverse_DCT_method_ptr inverse_DCT;
boolean first_row, last_row;
JCOEF * workspace;
JCOEF *workspace;
int *coef_bits;
JQUANT_TBL *quanttbl;
INT32 Q00,Q01,Q02,Q10,Q11,Q20, num;
JLONG Q00,Q01,Q02,Q10,Q11,Q20, num;
int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
int Al, pred;
@ -547,7 +492,7 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */
for (block_row = 0; block_row < block_rows; block_row++) {
buffer_ptr = buffer[block_row];
buffer_ptr = buffer[block_row] + cinfo->master->first_MCU_col[ci];
if (first_row && block_row == 0)
prev_block_row = buffer_ptr;
else
@ -564,7 +509,8 @@ decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
DC7 = DC8 = DC9 = (int) next_block_row[0][0];
output_col = 0;
last_block_column = compptr->width_in_blocks - 1;
for (block_num = 0; block_num <= last_block_column; block_num++) {
for (block_num = cinfo->master->first_MCU_col[ci];
block_num <= cinfo->master->last_MCU_col[ci]; block_num++) {
/* Fetch current DCT block into workspace so we can modify it. */
jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
/* Update DC values */

82
media/libjpeg/jdcoefct.h Normal file
View File

@ -0,0 +1,82 @@
/*
* jdcoefct.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#define JPEG_INTERNALS
#include "jpeglib.h"
/* Block smoothing is only applicable for progressive JPEG, so: */
#ifndef D_PROGRESSIVE_SUPPORTED
#undef BLOCK_SMOOTHING_SUPPORTED
#endif
/* Private buffer controller object */
typedef struct {
struct jpeg_d_coef_controller pub; /* public fields */
/* These variables keep track of the current location of the input side. */
/* cinfo->input_iMCU_row is also used for this. */
JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
int MCU_vert_offset; /* counts MCU rows within iMCU row */
int MCU_rows_per_iMCU_row; /* number of such rows needed */
/* The output side's location is represented by cinfo->output_iMCU_row. */
/* In single-pass modes, it's sufficient to buffer just one MCU.
* We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
* and let the entropy decoder write into that workspace each time.
* In multi-pass modes, this array points to the current MCU's blocks
* within the virtual arrays; it is used only by the input side.
*/
JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
/* Temporary workspace for one MCU */
JCOEF *workspace;
#ifdef D_MULTISCAN_FILES_SUPPORTED
/* In multi-pass modes, we need a virtual block array for each component. */
jvirt_barray_ptr whole_image[MAX_COMPONENTS];
#endif
#ifdef BLOCK_SMOOTHING_SUPPORTED
/* When doing block smoothing, we latch coefficient Al values here */
int *coef_bits_latch;
#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
#endif
} my_coef_controller;
typedef my_coef_controller *my_coef_ptr;
LOCAL(void)
start_iMCU_row (j_decompress_ptr cinfo)
/* Reset within-iMCU-row counters for a new row (input side) */
{
my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
/* In an interleaved scan, an MCU row is the same as an iMCU row.
* In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
* But at the bottom of the image, process only what's left.
*/
if (cinfo->comps_in_scan > 1) {
coef->MCU_rows_per_iMCU_row = 1;
} else {
if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
else
coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
}
coef->MCU_ctr = 0;
coef->MCU_vert_offset = 0;
}

View File

@ -5,8 +5,9 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modifications:
* Copyright (C) 2013, Linaro Limited.
* Copyright (C) 2014, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2014-2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains output colorspace conversion routines.
*/
@ -30,12 +31,12 @@ ycc_rgb565_convert_internal (j_decompress_ptr cinfo,
register JSAMPLE * range_limit = cinfo->sample_range_limit;
register int * Crrtab = cconvert->Cr_r_tab;
register int * Cbbtab = cconvert->Cb_b_tab;
register INT32 * Crgtab = cconvert->Cr_g_tab;
register INT32 * Cbgtab = cconvert->Cb_g_tab;
register JLONG * Crgtab = cconvert->Cr_g_tab;
register JLONG * Cbgtab = cconvert->Cb_g_tab;
SHIFT_TEMPS
while (--num_rows >= 0) {
INT32 rgb;
JLONG rgb;
unsigned int r, g, b;
inptr0 = input_buf[0][input_row];
inptr1 = input_buf[1][input_row];
@ -52,7 +53,7 @@ ycc_rgb565_convert_internal (j_decompress_ptr cinfo,
SCALEBITS))];
b = range_limit[y + Cbbtab[cb]];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
outptr += 2;
num_cols--;
}
@ -87,7 +88,7 @@ ycc_rgb565_convert_internal (j_decompress_ptr cinfo,
SCALEBITS))];
b = range_limit[y + Cbbtab[cb]];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
}
}
}
@ -109,13 +110,13 @@ ycc_rgb565D_convert_internal (j_decompress_ptr cinfo,
register JSAMPLE * range_limit = cinfo->sample_range_limit;
register int * Crrtab = cconvert->Cr_r_tab;
register int * Cbbtab = cconvert->Cb_b_tab;
register INT32 * Crgtab = cconvert->Cr_g_tab;
register INT32 * Cbgtab = cconvert->Cb_g_tab;
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
register JLONG * Crgtab = cconvert->Cr_g_tab;
register JLONG * Cbgtab = cconvert->Cb_g_tab;
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
SHIFT_TEMPS
while (--num_rows >= 0) {
INT32 rgb;
JLONG rgb;
unsigned int r, g, b;
inptr0 = input_buf[0][input_row];
@ -133,7 +134,7 @@ ycc_rgb565D_convert_internal (j_decompress_ptr cinfo,
SCALEBITS)), d0)];
b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
outptr += 2;
num_cols--;
}
@ -173,7 +174,7 @@ ycc_rgb565D_convert_internal (j_decompress_ptr cinfo,
SCALEBITS)), d0)];
b = range_limit[DITHER_565_B(y + Cbbtab[cb], d0)];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
}
}
}
@ -192,7 +193,7 @@ rgb_rgb565_convert_internal (j_decompress_ptr cinfo,
SHIFT_TEMPS
while (--num_rows >= 0) {
INT32 rgb;
JLONG rgb;
unsigned int r, g, b;
inptr0 = input_buf[0][input_row];
@ -205,7 +206,7 @@ rgb_rgb565_convert_internal (j_decompress_ptr cinfo,
g = GETJSAMPLE(*inptr1++);
b = GETJSAMPLE(*inptr2++);
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
outptr += 2;
num_cols--;
}
@ -228,7 +229,7 @@ rgb_rgb565_convert_internal (j_decompress_ptr cinfo,
g = GETJSAMPLE(*inptr1);
b = GETJSAMPLE(*inptr2);
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
}
}
}
@ -245,11 +246,11 @@ rgb_rgb565D_convert_internal (j_decompress_ptr cinfo,
register JDIMENSION col;
register JSAMPLE * range_limit = cinfo->sample_range_limit;
JDIMENSION num_cols = cinfo->output_width;
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
SHIFT_TEMPS
while (--num_rows >= 0) {
INT32 rgb;
JLONG rgb;
unsigned int r, g, b;
inptr0 = input_buf[0][input_row];
@ -262,7 +263,7 @@ rgb_rgb565D_convert_internal (j_decompress_ptr cinfo,
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1++), d0)];
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2++), d0)];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
outptr += 2;
num_cols--;
}
@ -287,7 +288,7 @@ rgb_rgb565D_convert_internal (j_decompress_ptr cinfo,
g = range_limit[DITHER_565_G(GETJSAMPLE(*inptr1), d0)];
b = range_limit[DITHER_565_B(GETJSAMPLE(*inptr2), d0)];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
}
}
}
@ -304,7 +305,7 @@ gray_rgb565_convert_internal (j_decompress_ptr cinfo,
JDIMENSION num_cols = cinfo->output_width;
while (--num_rows >= 0) {
INT32 rgb;
JLONG rgb;
unsigned int g;
inptr = input_buf[0][input_row++];
@ -312,7 +313,7 @@ gray_rgb565_convert_internal (j_decompress_ptr cinfo,
if (PACK_NEED_ALIGNMENT(outptr)) {
g = *inptr++;
rgb = PACK_SHORT_565(g, g, g);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
outptr += 2;
num_cols--;
}
@ -327,7 +328,7 @@ gray_rgb565_convert_internal (j_decompress_ptr cinfo,
if (num_cols & 1) {
g = *inptr;
rgb = PACK_SHORT_565(g, g, g);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
}
}
}
@ -343,10 +344,10 @@ gray_rgb565D_convert_internal (j_decompress_ptr cinfo,
register JDIMENSION col;
register JSAMPLE * range_limit = cinfo->sample_range_limit;
JDIMENSION num_cols = cinfo->output_width;
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
while (--num_rows >= 0) {
INT32 rgb;
JLONG rgb;
unsigned int g;
inptr = input_buf[0][input_row++];
@ -355,7 +356,7 @@ gray_rgb565D_convert_internal (j_decompress_ptr cinfo,
g = *inptr++;
g = range_limit[DITHER_565_R(g, d0)];
rgb = PACK_SHORT_565(g, g, g);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
outptr += 2;
num_cols--;
}
@ -377,7 +378,7 @@ gray_rgb565D_convert_internal (j_decompress_ptr cinfo,
g = *inptr;
g = range_limit[DITHER_565_R(g, d0)];
rgb = PACK_SHORT_565(g, g, g);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
}
}
}

View File

@ -4,8 +4,9 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2009, 2011, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2009, 2011, 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains output colorspace conversion routines.
*/
@ -41,8 +42,8 @@ ycc_rgb_convert_internal (j_decompress_ptr cinfo,
register JSAMPLE * range_limit = cinfo->sample_range_limit;
register int * Crrtab = cconvert->Cr_r_tab;
register int * Cbbtab = cconvert->Cb_b_tab;
register INT32 * Crgtab = cconvert->Cr_g_tab;
register INT32 * Cbgtab = cconvert->Cb_g_tab;
register JLONG * Crgtab = cconvert->Cr_g_tab;
register JLONG * Cbgtab = cconvert->Cb_g_tab;
SHIFT_TEMPS
while (--num_rows >= 0) {

View File

@ -8,7 +8,8 @@
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2009, 2011-2012, 2014-2015, D. R. Commander.
* Copyright (C) 2013, Linaro Limited.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains output colorspace conversion routines.
*/
@ -26,16 +27,16 @@ typedef struct {
struct jpeg_color_deconverter pub; /* public fields */
/* Private state for YCC->RGB conversion */
int * Cr_r_tab; /* => table for Cr to R conversion */
int * Cb_b_tab; /* => table for Cb to B conversion */
INT32 * Cr_g_tab; /* => table for Cr to G conversion */
INT32 * Cb_g_tab; /* => table for Cb to G conversion */
int *Cr_r_tab; /* => table for Cr to R conversion */
int *Cb_b_tab; /* => table for Cb to B conversion */
JLONG *Cr_g_tab; /* => table for Cr to G conversion */
JLONG *Cb_g_tab; /* => table for Cb to G conversion */
/* Private state for RGB->Y conversion */
INT32 * rgb_y_tab; /* => table for RGB to Y conversion */
JLONG *rgb_y_tab; /* => table for RGB to Y conversion */
} my_color_deconverter;
typedef my_color_deconverter * my_cconvert_ptr;
typedef my_color_deconverter *my_cconvert_ptr;
/**************** YCbCr -> RGB conversion: most common case **************/
@ -73,8 +74,8 @@ typedef my_color_deconverter * my_cconvert_ptr;
*/
#define SCALEBITS 16 /* speediest right-shift on some machines */
#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
#define ONE_HALF ((JLONG) 1 << (SCALEBITS-1))
#define FIX(x) ((JLONG) ((x) * (1L<<SCALEBITS) + 0.5))
/* We allocate one big table for RGB->Y conversion and divide it up into
* three parts, instead of doing three alloc_small requests. This lets us
@ -211,7 +212,7 @@ build_ycc_rgb_table (j_decompress_ptr cinfo)
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
int i;
INT32 x;
JLONG x;
SHIFT_TEMPS
cconvert->Cr_r_tab = (int *)
@ -220,12 +221,12 @@ build_ycc_rgb_table (j_decompress_ptr cinfo)
cconvert->Cb_b_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * sizeof(int));
cconvert->Cr_g_tab = (INT32 *)
cconvert->Cr_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * sizeof(INT32));
cconvert->Cb_g_tab = (INT32 *)
(MAXJSAMPLE+1) * sizeof(JLONG));
cconvert->Cb_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * sizeof(INT32));
(MAXJSAMPLE+1) * sizeof(JLONG));
for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
/* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
@ -302,13 +303,13 @@ LOCAL(void)
build_rgb_y_table (j_decompress_ptr cinfo)
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
INT32 * rgb_y_tab;
INT32 i;
JLONG *rgb_y_tab;
JLONG i;
/* Allocate and fill in the conversion tables. */
cconvert->rgb_y_tab = rgb_y_tab = (INT32 *)
cconvert->rgb_y_tab = rgb_y_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(TABLE_SIZE * sizeof(INT32)));
(TABLE_SIZE * sizeof(JLONG)));
for (i = 0; i <= MAXJSAMPLE; i++) {
rgb_y_tab[i+R_Y_OFF] = FIX(0.29900) * i;
@ -329,7 +330,7 @@ rgb_gray_convert (j_decompress_ptr cinfo,
{
my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
register int r, g, b;
register INT32 * ctab = cconvert->rgb_y_tab;
register JLONG *ctab = cconvert->rgb_y_tab;
register JSAMPROW outptr;
register JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
@ -542,11 +543,11 @@ ycck_cmyk_convert (j_decompress_ptr cinfo,
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
register JSAMPLE * range_limit = cinfo->sample_range_limit;
register int * Crrtab = cconvert->Cr_r_tab;
register int * Cbbtab = cconvert->Cb_b_tab;
register INT32 * Crgtab = cconvert->Cr_g_tab;
register INT32 * Cbgtab = cconvert->Cb_g_tab;
register JSAMPLE *range_limit = cinfo->sample_range_limit;
register int *Crrtab = cconvert->Cr_r_tab;
register int *Cbbtab = cconvert->Cb_b_tab;
register JLONG *Crgtab = cconvert->Cr_g_tab;
register JLONG *Cbgtab = cconvert->Cb_g_tab;
SHIFT_TEMPS
while (--num_rows >= 0) {
@ -603,8 +604,8 @@ ycck_cmyk_convert (j_decompress_ptr cinfo,
*/
#define DITHER_MASK 0x3
#define DITHER_ROTATE(x) (((x) << 24) | (((x) >> 8) & 0x00FFFFFF))
static const INT32 dither_matrix[4] = {
#define DITHER_ROTATE(x) ((((x) & 0xFF) << 24) | (((x) >> 8) & 0x00FFFFFF))
static const JLONG dither_matrix[4] = {
0x0008020A,
0x0C040E06,
0x030B0109,

View File

@ -3,9 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* libjpeg-turbo Modifications:
* Copyright (C) 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This include file contains common declarations for the forward and
* inverse DCT modules. These declarations are private to the DCT managers
@ -18,7 +19,7 @@
/*
* A forward DCT routine is given a pointer to a work area of type DCTELEM[];
* the DCT is to be performed in-place in that buffer. Type DCTELEM is int
* for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT
* for 8-bit samples, JLONG for 12-bit samples. (NOTE: Floating-point DCT
* implementations use an array of type FAST_FLOAT, instead.)
* The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
* The DCT outputs are returned scaled up by a factor of 8; they therefore
@ -40,7 +41,7 @@ typedef unsigned short UDCTELEM;
typedef unsigned int UDCTELEM2;
#endif
#else
typedef INT32 DCTELEM; /* must have 32 bits */
typedef JLONG DCTELEM; /* must have 32 bits */
typedef unsigned long long UDCTELEM2;
#endif
@ -67,7 +68,7 @@ typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
#else
typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
typedef JLONG IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
#endif
typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
@ -89,63 +90,63 @@ typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
/* Extern declarations for the forward and inverse DCT routines. */
EXTERN(void) jpeg_fdct_islow (DCTELEM * data);
EXTERN(void) jpeg_fdct_ifast (DCTELEM * data);
EXTERN(void) jpeg_fdct_float (FAST_FLOAT * data);
EXTERN(void) jpeg_fdct_islow (DCTELEM *data);
EXTERN(void) jpeg_fdct_ifast (DCTELEM *data);
EXTERN(void) jpeg_fdct_float (FAST_FLOAT *data);
EXTERN(void) jpeg_idct_islow
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_ifast
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_float
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_7x7
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_6x6
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_5x5
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_4x4
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_3x3
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_2x2
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_1x1
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_9x9
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_10x10
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_11x11
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_12x12
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_13x13
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_14x14
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_15x15
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
EXTERN(void) jpeg_idct_16x16
(j_decompress_ptr cinfo, jpeg_component_info * compptr,
(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col);
@ -153,13 +154,13 @@ EXTERN(void) jpeg_idct_16x16
* Macros for handling fixed-point arithmetic; these are used by many
* but not all of the DCT/IDCT modules.
*
* All values are expected to be of type INT32.
* All values are expected to be of type JLONG.
* Fractional constants are scaled left by CONST_BITS bits.
* CONST_BITS is defined within each module using these macros,
* and may differ from one module to the next.
*/
#define ONE ((INT32) 1)
#define ONE ((JLONG) 1)
#define CONST_SCALE (ONE << CONST_BITS)
/* Convert a positive real constant to an integer scaled by CONST_SCALE.
@ -167,16 +168,16 @@ EXTERN(void) jpeg_idct_16x16
* thus causing a lot of useless floating-point operations at run time.
*/
#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5))
#define FIX(x) ((JLONG) ((x) * CONST_SCALE + 0.5))
/* Descale and correctly round an INT32 value that's scaled by N bits.
/* Descale and correctly round a JLONG value that's scaled by N bits.
* We assume RIGHT_SHIFT rounds towards minus infinity, so adding
* the fudge factor is correct for either sign of X.
*/
#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
/* Multiply a JLONG variable by a JLONG constant to yield a JLONG result.
* This macro is used only when the two inputs will actually be no more than
* 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
* full 32x32 multiply. This provides a useful speedup on many machines.
@ -189,7 +190,7 @@ EXTERN(void) jpeg_idct_16x16
#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const)))
#endif
#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const)))
#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((JLONG) (const)))
#endif
#ifndef MULTIPLY16C16 /* default definition */

View File

@ -6,9 +6,10 @@
* Modified 2002-2010 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2010, D. R. Commander.
* Copyright (C) 2013, MIPS Technologies, Inc., California
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2010, 2015, D. R. Commander.
* Copyright (C) 2013, MIPS Technologies, Inc., California.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the inverse-DCT management logic.
* This code selects a particular IDCT implementation to be used,
@ -58,7 +59,7 @@ typedef struct {
int cur_method[MAX_COMPONENTS];
} my_idct_controller;
typedef my_idct_controller * my_idct_ptr;
typedef my_idct_controller *my_idct_ptr;
/* Allocated multiplier tables: big enough for any supported variant */
@ -100,7 +101,7 @@ start_pass (j_decompress_ptr cinfo)
jpeg_component_info *compptr;
int method = 0;
inverse_DCT_method_ptr method_ptr = NULL;
JQUANT_TBL * qtbl;
JQUANT_TBL *qtbl;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@ -245,7 +246,7 @@ start_pass (j_decompress_ptr cinfo)
/* For LL&M IDCT method, multipliers are equal to raw quantization
* coefficients, but are stored as ints to ensure access efficiency.
*/
ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
ISLOW_MULT_TYPE *ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
for (i = 0; i < DCTSIZE2; i++) {
ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i];
}
@ -262,7 +263,7 @@ start_pass (j_decompress_ptr cinfo)
* For integer operation, the multiplier table is to be scaled by
* IFAST_SCALE_BITS.
*/
IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
IFAST_MULT_TYPE *ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
#define CONST_BITS 14
static const INT16 aanscales[DCTSIZE2] = {
/* precomputed values scaled up by 14 bits */
@ -279,8 +280,8 @@ start_pass (j_decompress_ptr cinfo)
for (i = 0; i < DCTSIZE2; i++) {
ifmtbl[i] = (IFAST_MULT_TYPE)
DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
(INT32) aanscales[i]),
DESCALE(MULTIPLY16V16((JLONG) qtbl->quantval[i],
(JLONG) aanscales[i]),
CONST_BITS-IFAST_SCALE_BITS);
}
}
@ -294,7 +295,7 @@ start_pass (j_decompress_ptr cinfo)
* scalefactor[0] = 1
* scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
*/
FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
FLOAT_MULT_TYPE *fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
int row, col;
static const double aanscalefactor[DCTSIZE] = {
1.0, 1.387039845, 1.306562965, 1.175875602,

View File

@ -4,8 +4,9 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2009-2011, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2009-2011, 2016, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains Huffman entropy decoding routines.
*
@ -66,20 +67,20 @@ typedef struct {
unsigned int restarts_to_go; /* MCUs left in this restart interval */
/* Pointers to derived tables (these workspaces have image lifespan) */
d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
d_derived_tbl *dc_derived_tbls[NUM_HUFF_TBLS];
d_derived_tbl *ac_derived_tbls[NUM_HUFF_TBLS];
/* Precalculated info set up by start_pass for use in decode_mcu: */
/* Pointers to derived tables to be used for each block within an MCU */
d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];
d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];
d_derived_tbl *dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];
d_derived_tbl *ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];
/* Whether we care about the DC and AC coefficient values for each block */
boolean dc_needed[D_MAX_BLOCKS_IN_MCU];
boolean ac_needed[D_MAX_BLOCKS_IN_MCU];
} huff_entropy_decoder;
typedef huff_entropy_decoder * huff_entropy_ptr;
typedef huff_entropy_decoder *huff_entropy_ptr;
/*
@ -92,7 +93,7 @@ start_pass_huff_decoder (j_decompress_ptr cinfo)
huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
int ci, blkn, dctbl, actbl;
d_derived_tbl **pdtbl;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
/* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
* This ought to be an error condition, but we make it a warning because
@ -152,7 +153,7 @@ start_pass_huff_decoder (j_decompress_ptr cinfo)
GLOBAL(void)
jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
d_derived_tbl ** pdtbl)
d_derived_tbl **pdtbl)
{
JHUFF_TBL *htbl;
d_derived_tbl *dtbl;
@ -209,7 +210,7 @@ jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
/* code is now 1 more than the last code used for codelength si; but
* it must still fit in si bits, since no code is allowed to be all ones.
*/
if (((INT32) code) >= (((INT32) 1) << si))
if (((JLONG) code) >= (((JLONG) 1) << si))
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
code <<= 1;
si++;
@ -223,7 +224,7 @@ jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
/* valoffset[l] = huffval[] index of 1st symbol of code length l,
* minus the minimum code of length l
*/
dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p];
dtbl->valoffset[l] = (JLONG) p - (JLONG) huffcode[p];
p += htbl->bits[l];
dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
} else {
@ -295,13 +296,13 @@ jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
GLOBAL(boolean)
jpeg_fill_bit_buffer (bitread_working_state * state,
jpeg_fill_bit_buffer (bitread_working_state *state,
register bit_buf_type get_buffer, register int bits_left,
int nbits)
/* Load up the bit buffer to a depth of at least nbits */
{
/* Copy heavily used state fields into locals (hopefully registers) */
register const JOCTET * next_input_byte = state->next_input_byte;
register const JOCTET *next_input_byte = state->next_input_byte;
register size_t bytes_in_buffer = state->bytes_in_buffer;
j_decompress_ptr cinfo = state->cinfo;
@ -445,12 +446,12 @@ jpeg_fill_bit_buffer (bitread_working_state * state,
*/
GLOBAL(int)
jpeg_huff_decode (bitread_working_state * state,
jpeg_huff_decode (bitread_working_state *state,
register bit_buf_type get_buffer, register int bits_left,
d_derived_tbl * htbl, int min_bits)
d_derived_tbl *htbl, int min_bits)
{
register int l = min_bits;
register INT32 code;
register JLONG code;
/* HUFF_DECODE has determined that the code is at least min_bits */
/* bits long, so fetch that many bits in one swoop. */
@ -564,9 +565,9 @@ decode_mcu_slow (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
ASSIGN_STATE(state, entropy->saved);
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
JBLOCKROW block = MCU_data[blkn];
d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
d_derived_tbl *dctbl = entropy->dc_cur_tbls[blkn];
d_derived_tbl *actbl = entropy->ac_cur_tbls[blkn];
register int s, k, r;
/* Decode a single block's worth of coefficients */
@ -584,11 +585,13 @@ decode_mcu_slow (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
int ci = cinfo->MCU_membership[blkn];
s += state.last_dc_val[ci];
state.last_dc_val[ci] = s;
/* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
(*block)[0] = (JCOEF) s;
if (block) {
/* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
(*block)[0] = (JCOEF) s;
}
}
if (entropy->ac_needed[blkn]) {
if (entropy->ac_needed[blkn] && block) {
/* Section F.2.2.2: decode the AC coefficients */
/* Since zeroes are skipped, output area must be cleared beforehand */
@ -661,9 +664,9 @@ decode_mcu_fast (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
ASSIGN_STATE(state, entropy->saved);
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
JBLOCKROW block = MCU_data[blkn];
d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
d_derived_tbl *dctbl = entropy->dc_cur_tbls[blkn];
d_derived_tbl *actbl = entropy->ac_cur_tbls[blkn];
register int s, k, r, l;
HUFF_DECODE_FAST(s, l, dctbl, slow_decode_mcu);
@ -677,10 +680,11 @@ decode_mcu_fast (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
int ci = cinfo->MCU_membership[blkn];
s += state.last_dc_val[ci];
state.last_dc_val[ci] = s;
(*block)[0] = (JCOEF) s;
if (block)
(*block)[0] = (JCOEF) s;
}
if (entropy->ac_needed[blkn]) {
if (entropy->ac_needed[blkn] && block) {
for (k = 1; k < DCTSIZE2; k++) {
HUFF_DECODE_FAST(s, l, actbl, slow_decode_mcu);
@ -747,7 +751,7 @@ slow_decode_mcu:
* this module, since we'll just re-assign them on the next call.)
*/
#define BUFSIZE (DCTSIZE2 * 2)
#define BUFSIZE (DCTSIZE2 * 8)
METHODDEF(boolean)
decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)

View File

@ -4,14 +4,17 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2010-2011, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2010-2011, 2015-2016, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains declarations for Huffman entropy decoding routines
* that are shared between the sequential decoder (jdhuff.c) and the
* progressive decoder (jdphuff.c). No other modules need to see these.
*/
#include "jconfigint.h"
/* Derived data constructed for each Huffman table */
@ -19,9 +22,9 @@
typedef struct {
/* Basic tables: (element [0] of each array is unused) */
INT32 maxcode[18]; /* largest code of length k (-1 if none) */
JLONG maxcode[18]; /* largest code of length k (-1 if none) */
/* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
INT32 valoffset[18]; /* huffval[] offset for codes of length k */
JLONG valoffset[18]; /* huffval[] offset for codes of length k */
/* valoffset[k] = huffval[] index of 1st symbol of code length k, less
* the smallest code of length k; so given a code of length k, the
* corresponding symbol is huffval[code + valoffset[k]]
@ -73,12 +76,12 @@ EXTERN(void) jpeg_make_d_derived_tbl
#if SIZEOF_SIZE_T==8 || defined(_WIN64)
typedef size_t bit_buf_type; /* type of bit-extraction buffer */
typedef size_t bit_buf_type; /* type of bit-extraction buffer */
#define BIT_BUF_SIZE 64 /* size of buffer in bits */
#else
typedef INT32 bit_buf_type; /* type of bit-extraction buffer */
typedef unsigned long bit_buf_type; /* type of bit-extraction buffer */
#define BIT_BUF_SIZE 32 /* size of buffer in bits */
#endif
@ -98,7 +101,7 @@ typedef struct { /* Bitreading state saved across MCUs */
typedef struct { /* Bitreading working state within an MCU */
/* Current data source location */
/* We need a copy, rather than munging the original, in case of suspension */
const JOCTET * next_input_byte; /* => next byte to read from source */
const JOCTET *next_input_byte; /* => next byte to read from source */
size_t bytes_in_buffer; /* # of bytes remaining in source buffer */
/* Bit input buffer --- note these values are kept in register variables,
* not in this struct, inside the inner loops.
@ -163,7 +166,7 @@ typedef struct { /* Bitreading working state within an MCU */
/* Load up the bit buffer to a depth of at least nbits */
EXTERN(boolean) jpeg_fill_bit_buffer
(bitread_working_state * state, register bit_buf_type get_buffer,
(bitread_working_state *state, register bit_buf_type get_buffer,
register int bits_left, int nbits);
@ -229,5 +232,5 @@ slowlabel: \
/* Out-of-line case for Huffman code fetching */
EXTERN(int) jpeg_huff_decode
(bitread_working_state * state, register bit_buf_type get_buffer,
register int bits_left, d_derived_tbl * htbl, int min_bits);
(bitread_working_state *state, register bit_buf_type get_buffer,
register int bits_left, d_derived_tbl *htbl, int min_bits);

View File

@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2010, 2016, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains input control logic for the JPEG decompressor.
* These routines are concerned with controlling the decompressor's input
@ -27,7 +29,7 @@ typedef struct {
boolean inheaders; /* TRUE until first SOS is reached */
} my_input_controller;
typedef my_input_controller * my_inputctl_ptr;
typedef my_input_controller *my_inputctl_ptr;
/* Forward declarations */
@ -104,6 +106,11 @@ initial_setup (j_decompress_ptr cinfo)
compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
(long) (cinfo->max_v_samp_factor * DCTSIZE));
/* Set the first and last MCU columns to decompress from multi-scan images.
* By default, decompress all of the MCU columns.
*/
cinfo->master->first_MCU_col[ci] = 0;
cinfo->master->last_MCU_col[ci] = compptr->width_in_blocks - 1;
/* downsampled_width and downsampled_height will also be overridden by
* jdmaster.c if we are doing full decompression. The transcoder library
* doesn't use these values, but the calling application might.
@ -238,7 +245,7 @@ latch_quant_tables (j_decompress_ptr cinfo)
{
int ci, qtblno;
jpeg_component_info *compptr;
JQUANT_TBL * qtbl;
JQUANT_TBL *qtbl;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];

View File

@ -4,8 +4,9 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2010, 2016, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the main buffer controller for decompression.
* The main buffer lies between the JPEG decompressor proper and the
@ -15,10 +16,8 @@
* supplies the equivalent of the main buffer in that case.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jpegcomp.h"
#include "jdmainct.h"
/*
@ -112,36 +111,6 @@
*/
/* Private buffer controller object */
typedef struct {
struct jpeg_d_main_controller pub; /* public fields */
/* Pointer to allocated workspace (M or M+2 row groups). */
JSAMPARRAY buffer[MAX_COMPONENTS];
boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
/* Remaining fields are only used in the context case. */
/* These are the master pointers to the funny-order pointer lists. */
JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
int whichptr; /* indicates which pointer set is now in use */
int context_state; /* process_data state machine status */
JDIMENSION rowgroups_avail; /* row groups available to postprocessor */
JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
} my_main_controller;
typedef my_main_controller * my_main_ptr;
/* context_state values: */
#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */
#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */
#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */
/* Forward declarations */
METHODDEF(void) process_data_simple_main
(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
@ -237,34 +206,6 @@ make_funny_pointers (j_decompress_ptr cinfo)
}
LOCAL(void)
set_wraparound_pointers (j_decompress_ptr cinfo)
/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
* This changes the pointer list state from top-of-image to the normal state.
*/
{
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
int ci, i, rgroup;
int M = cinfo->_min_DCT_scaled_size;
jpeg_component_info *compptr;
JSAMPARRAY xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
cinfo->_min_DCT_scaled_size; /* height of a row group of component */
xbuf0 = main_ptr->xbuffer[0][ci];
xbuf1 = main_ptr->xbuffer[1][ci];
for (i = 0; i < rgroup; i++) {
xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
xbuf0[rgroup*(M+2) + i] = xbuf0[i];
xbuf1[rgroup*(M+2) + i] = xbuf1[i];
}
}
}
LOCAL(void)
set_bottom_pointers (j_decompress_ptr cinfo)
/* Change the pointer lists to duplicate the last sample row at the bottom

71
media/libjpeg/jdmainct.h Normal file
View File

@ -0,0 +1,71 @@
/*
* jdmainct.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#define JPEG_INTERNALS
#include "jpeglib.h"
#include "jpegcomp.h"
/* Private buffer controller object */
typedef struct {
struct jpeg_d_main_controller pub; /* public fields */
/* Pointer to allocated workspace (M or M+2 row groups). */
JSAMPARRAY buffer[MAX_COMPONENTS];
boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
/* Remaining fields are only used in the context case. */
/* These are the master pointers to the funny-order pointer lists. */
JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
int whichptr; /* indicates which pointer set is now in use */
int context_state; /* process_data state machine status */
JDIMENSION rowgroups_avail; /* row groups available to postprocessor */
JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
} my_main_controller;
typedef my_main_controller *my_main_ptr;
/* context_state values: */
#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */
#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */
#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */
LOCAL(void)
set_wraparound_pointers (j_decompress_ptr cinfo)
/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
* This changes the pointer list state from top-of-image to the normal state.
*/
{
my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
int ci, i, rgroup;
int M = cinfo->_min_DCT_scaled_size;
jpeg_component_info *compptr;
JSAMPARRAY xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
cinfo->_min_DCT_scaled_size; /* height of a row group of component */
xbuf0 = main_ptr->xbuffer[0][ci];
xbuf1 = main_ptr->xbuffer[1][ci];
for (i = 0; i < rgroup; i++) {
xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
xbuf0[rgroup*(M+2) + i] = xbuf0[i];
xbuf1[rgroup*(M+2) + i] = xbuf1[i];
}
}
}

View File

@ -4,8 +4,9 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2012, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2012, 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains routines to decode JPEG datastream markers.
* Most of the complexity arises from our desire to support input
@ -106,7 +107,7 @@ typedef struct {
/* Note: cur_marker is not linked into marker_list until it's all read. */
} my_marker_reader;
typedef my_marker_reader * my_marker_ptr;
typedef my_marker_reader *my_marker_ptr;
/*
@ -119,8 +120,8 @@ typedef my_marker_reader * my_marker_ptr;
/* Declare and initialize local copies of input pointer/count */
#define INPUT_VARS(cinfo) \
struct jpeg_source_mgr * datasrc = (cinfo)->src; \
const JOCTET * next_input_byte = datasrc->next_input_byte; \
struct jpeg_source_mgr *datasrc = (cinfo)->src; \
const JOCTET *next_input_byte = datasrc->next_input_byte; \
size_t bytes_in_buffer = datasrc->bytes_in_buffer
/* Unload the local copies --- do this only at a restart boundary */
@ -153,7 +154,7 @@ typedef my_marker_reader * my_marker_ptr;
V = GETJOCTET(*next_input_byte++); )
/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
* V should be declared unsigned int or perhaps INT32.
* V should be declared unsigned int or perhaps JLONG.
*/
#define INPUT_2BYTES(cinfo,V,action) \
MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
@ -239,9 +240,9 @@ LOCAL(boolean)
get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith)
/* Process a SOFn marker */
{
INT32 length;
JLONG length;
int c, ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
INPUT_VARS(cinfo);
cinfo->progressive_mode = is_prog;
@ -303,9 +304,9 @@ LOCAL(boolean)
get_sos (j_decompress_ptr cinfo)
/* Process a SOS marker */
{
INT32 length;
JLONG length;
int i, ci, n, c, cc, pi;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
INPUT_VARS(cinfo);
if (! cinfo->marker->saw_SOF)
@ -386,7 +387,7 @@ LOCAL(boolean)
get_dac (j_decompress_ptr cinfo)
/* Process a DAC marker */
{
INT32 length;
JLONG length;
int index, val;
INPUT_VARS(cinfo);
@ -432,7 +433,7 @@ LOCAL(boolean)
get_dht (j_decompress_ptr cinfo)
/* Process a DHT marker */
{
INT32 length;
JLONG length;
UINT8 bits[17];
UINT8 huffval[256];
int i, index, count;
@ -466,7 +467,7 @@ get_dht (j_decompress_ptr cinfo)
/* Here we just do minimal validation of the counts to avoid walking
* off the end of our table space. jdhuff.c will check more carefully.
*/
if (count > 256 || ((INT32) count) > length)
if (count > 256 || ((JLONG) count) > length)
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
for (i = 0; i < count; i++)
@ -506,7 +507,7 @@ LOCAL(boolean)
get_dqt (j_decompress_ptr cinfo)
/* Process a DQT marker */
{
INT32 length;
JLONG length;
int n, i, prec;
unsigned int tmp;
JQUANT_TBL *quant_ptr;
@ -564,7 +565,7 @@ LOCAL(boolean)
get_dri (j_decompress_ptr cinfo)
/* Process a DRI marker */
{
INT32 length;
JLONG length;
unsigned int tmp;
INPUT_VARS(cinfo);
@ -597,14 +598,14 @@ get_dri (j_decompress_ptr cinfo)
LOCAL(void)
examine_app0 (j_decompress_ptr cinfo, JOCTET * data,
unsigned int datalen, INT32 remaining)
examine_app0 (j_decompress_ptr cinfo, JOCTET *data,
unsigned int datalen, JLONG remaining)
/* Examine first few bytes from an APP0.
* Take appropriate action if it is a JFIF marker.
* datalen is # of bytes at data[], remaining is length of rest of marker data.
*/
{
INT32 totallen = (INT32) datalen + remaining;
JLONG totallen = (JLONG) datalen + remaining;
if (datalen >= APP0_DATA_LEN &&
GETJOCTET(data[0]) == 0x4A &&
@ -638,7 +639,7 @@ examine_app0 (j_decompress_ptr cinfo, JOCTET * data,
GETJOCTET(data[12]), GETJOCTET(data[13]));
totallen -= APP0_DATA_LEN;
if (totallen !=
((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3))
((JLONG)GETJOCTET(data[12]) * (JLONG)GETJOCTET(data[13]) * (JLONG) 3))
TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen);
} else if (datalen >= 6 &&
GETJOCTET(data[0]) == 0x4A &&
@ -673,8 +674,8 @@ examine_app0 (j_decompress_ptr cinfo, JOCTET * data,
LOCAL(void)
examine_app14 (j_decompress_ptr cinfo, JOCTET * data,
unsigned int datalen, INT32 remaining)
examine_app14 (j_decompress_ptr cinfo, JOCTET *data,
unsigned int datalen, JLONG remaining)
/* Examine first few bytes from an APP14.
* Take appropriate action if it is an Adobe marker.
* datalen is # of bytes at data[], remaining is length of rest of marker data.
@ -707,7 +708,7 @@ METHODDEF(boolean)
get_interesting_appn (j_decompress_ptr cinfo)
/* Process an APP0 or APP14 marker without saving it */
{
INT32 length;
JLONG length;
JOCTET b[APPN_DATA_LEN];
unsigned int i, numtoread;
INPUT_VARS(cinfo);
@ -758,8 +759,8 @@ save_marker (j_decompress_ptr cinfo)
my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
jpeg_saved_marker_ptr cur_marker = marker->cur_marker;
unsigned int bytes_read, data_length;
JOCTET * data;
INT32 length = 0;
JOCTET *data;
JLONG length = 0;
INPUT_VARS(cinfo);
if (cur_marker == NULL) {
@ -861,7 +862,7 @@ METHODDEF(boolean)
skip_variable (j_decompress_ptr cinfo)
/* Skip over an unknown or uninteresting variable-length marker */
{
INT32 length;
JLONG length;
INPUT_VARS(cinfo);
INPUT_2BYTES(cinfo, length, return FALSE);

View File

@ -5,9 +5,11 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2002-2009 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2009-2011, D. R. Commander.
* Copyright (C) 2009-2011, 2016, D. R. Commander.
* Copyright (C) 2013, Linaro Limited.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains master control logic for the JPEG decompressor.
* These routines are concerned with selecting the modules to be executed
@ -19,25 +21,7 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jpegcomp.h"
/* Private state */
typedef struct {
struct jpeg_decomp_master pub; /* public fields */
int pass_number; /* # of passes completed */
boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
/* Saved references to initialized quantizer modules,
* in case we need to switch modes.
*/
struct jpeg_color_quantizer * quantizer_1pass;
struct jpeg_color_quantizer * quantizer_2pass;
} my_decomp_master;
typedef my_decomp_master * my_master_ptr;
#include "jdmaster.h"
/*
@ -424,7 +408,7 @@ LOCAL(void)
prepare_range_limit_table (j_decompress_ptr cinfo)
/* Allocate and fill in the sample_range_limit table */
{
JSAMPLE * table;
JSAMPLE *table;
int i;
table = (JSAMPLE *)
@ -578,6 +562,12 @@ master_selection (j_decompress_ptr cinfo)
/* Initialize input side of decompressor to consume first scan. */
(*cinfo->inputctl->start_input_pass) (cinfo);
/* Set the first and last iMCU columns to decompress from single-scan images.
* By default, decompress all of the iMCU columns.
*/
cinfo->master->first_iMCU_col = 0;
cinfo->master->last_iMCU_col = cinfo->MCUs_per_row - 1;
#ifdef D_MULTISCAN_FILES_SUPPORTED
/* If jpeg_start_decompress will read the whole file, initialize
* progress monitoring appropriately. The input step is counted
@ -722,16 +712,13 @@ jpeg_new_colormap (j_decompress_ptr cinfo)
GLOBAL(void)
jinit_master_decompress (j_decompress_ptr cinfo)
{
my_master_ptr master;
my_master_ptr master = (my_master_ptr) cinfo->master;
master = (my_master_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
sizeof(my_decomp_master));
cinfo->master = (struct jpeg_decomp_master *) master;
master->pub.prepare_for_output_pass = prepare_for_output_pass;
master->pub.finish_output_pass = finish_output_pass;
master->pub.is_dummy_pass = FALSE;
master->pub.jinit_upsampler_no_alloc = FALSE;
master_selection(cinfo);
}

28
media/libjpeg/jdmaster.h Normal file
View File

@ -0,0 +1,28 @@
/*
* jdmaster.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1995, Thomas G. Lane.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the master control structure for the JPEG decompressor.
*/
/* Private state */
typedef struct {
struct jpeg_decomp_master pub; /* public fields */
int pass_number; /* # of passes completed */
boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
/* Saved references to initialized quantizer modules,
* in case we need to switch modes.
*/
struct jpeg_color_quantizer *quantizer_1pass;
struct jpeg_color_quantizer *quantizer_2pass;
} my_decomp_master;
typedef my_decomp_master *my_master_ptr;

View File

@ -3,11 +3,12 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* libjpeg-turbo Modifications:
* Copyright (C) 2009, 2011, 2014 D. R. Commander.
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2009, 2011, 2014-2015, D. R. Commander.
* Copyright (C) 2013, Linaro Limited.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains code for merged upsampling/color conversion.
*
@ -55,10 +56,10 @@ typedef struct {
JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
/* Private state for YCC->RGB conversion */
int * Cr_r_tab; /* => table for Cr to R conversion */
int * Cb_b_tab; /* => table for Cb to B conversion */
INT32 * Cr_g_tab; /* => table for Cr to G conversion */
INT32 * Cb_g_tab; /* => table for Cb to G conversion */
int *Cr_r_tab; /* => table for Cr to R conversion */
int *Cb_b_tab; /* => table for Cb to B conversion */
JLONG *Cr_g_tab; /* => table for Cr to G conversion */
JLONG *Cb_g_tab; /* => table for Cb to G conversion */
/* For 2:1 vertical sampling, we produce two output rows at a time.
* We need a "spare" row buffer to hold the second output row if the
@ -72,11 +73,11 @@ typedef struct {
JDIMENSION rows_to_go; /* counts rows remaining in image */
} my_upsampler;
typedef my_upsampler * my_upsample_ptr;
typedef my_upsampler *my_upsample_ptr;
#define SCALEBITS 16 /* speediest right-shift on some machines */
#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
#define ONE_HALF ((JLONG) 1 << (SCALEBITS-1))
#define FIX(x) ((JLONG) ((x) * (1L<<SCALEBITS) + 0.5))
/* Include inline routines for colorspace extensions */
@ -190,7 +191,7 @@ build_ycc_rgb_table (j_decompress_ptr cinfo)
{
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
int i;
INT32 x;
JLONG x;
SHIFT_TEMPS
upsample->Cr_r_tab = (int *)
@ -199,12 +200,12 @@ build_ycc_rgb_table (j_decompress_ptr cinfo)
upsample->Cb_b_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * sizeof(int));
upsample->Cr_g_tab = (INT32 *)
upsample->Cr_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * sizeof(INT32));
upsample->Cb_g_tab = (INT32 *)
(MAXJSAMPLE+1) * sizeof(JLONG));
upsample->Cb_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
(MAXJSAMPLE+1) * sizeof(INT32));
(MAXJSAMPLE+1) * sizeof(JLONG));
for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
/* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
@ -435,12 +436,12 @@ h2v2_merged_upsample (j_decompress_ptr cinfo,
#define PACK_NEED_ALIGNMENT(ptr) (((size_t)(ptr)) & 3)
#define WRITE_TWO_PIXELS_LE(addr, pixels) { \
((INT16*)(addr))[0] = (pixels); \
((INT16*)(addr))[1] = (pixels) >> 16; \
((INT16*)(addr))[0] = (INT16)(pixels); \
((INT16*)(addr))[1] = (INT16)((pixels) >> 16); \
}
#define WRITE_TWO_PIXELS_BE(addr, pixels) { \
((INT16*)(addr))[1] = (pixels); \
((INT16*)(addr))[0] = (pixels) >> 16; \
((INT16*)(addr))[1] = (INT16)(pixels); \
((INT16*)(addr))[0] = (INT16)((pixels) >> 16); \
}
#define DITHER_565_R(r, dither) ((r) + ((dither) & 0xFF))
@ -455,8 +456,8 @@ h2v2_merged_upsample (j_decompress_ptr cinfo,
*/
#define DITHER_MASK 0x3
#define DITHER_ROTATE(x) (((x) << 24) | (((x) >> 8) & 0x00FFFFFF))
static const INT32 dither_matrix[4] = {
#define DITHER_ROTATE(x) ((((x) & 0xFF) << 24) | (((x) >> 8) & 0x00FFFFFF))
static const JLONG dither_matrix[4] = {
0x0008020A,
0x0C040E06,
0x030B0109,

View File

@ -5,8 +5,9 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2013, Linaro Limited.
* Copyright (C) 2014, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2014-2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains code for merged upsampling/color conversion.
*/
@ -29,10 +30,10 @@ h2v1_merged_upsample_565_internal (j_decompress_ptr cinfo,
register JSAMPLE * range_limit = cinfo->sample_range_limit;
int * Crrtab = upsample->Cr_r_tab;
int * Cbbtab = upsample->Cb_b_tab;
INT32 * Crgtab = upsample->Cr_g_tab;
INT32 * Cbgtab = upsample->Cb_g_tab;
JLONG * Crgtab = upsample->Cr_g_tab;
JLONG * Cbgtab = upsample->Cb_g_tab;
unsigned int r, g, b;
INT32 rgb;
JLONG rgb;
SHIFT_TEMPS
inptr0 = input_buf[0][in_row_group_ctr];
@ -78,7 +79,7 @@ h2v1_merged_upsample_565_internal (j_decompress_ptr cinfo,
g = range_limit[y + cgreen];
b = range_limit[y + cblue];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
}
}
@ -100,11 +101,11 @@ h2v1_merged_upsample_565D_internal (j_decompress_ptr cinfo,
register JSAMPLE * range_limit = cinfo->sample_range_limit;
int * Crrtab = upsample->Cr_r_tab;
int * Cbbtab = upsample->Cb_b_tab;
INT32 * Crgtab = upsample->Cr_g_tab;
INT32 * Cbgtab = upsample->Cb_g_tab;
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
JLONG * Crgtab = upsample->Cr_g_tab;
JLONG * Cbgtab = upsample->Cb_g_tab;
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
unsigned int r, g, b;
INT32 rgb;
JLONG rgb;
SHIFT_TEMPS
inptr0 = input_buf[0][in_row_group_ctr];
@ -152,7 +153,7 @@ h2v1_merged_upsample_565D_internal (j_decompress_ptr cinfo,
g = range_limit[DITHER_565_G(y + cgreen, d0)];
b = range_limit[DITHER_565_B(y + cblue, d0)];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr = rgb;
*(INT16*)outptr = (INT16)rgb;
}
}
@ -174,10 +175,10 @@ h2v2_merged_upsample_565_internal (j_decompress_ptr cinfo,
register JSAMPLE * range_limit = cinfo->sample_range_limit;
int * Crrtab = upsample->Cr_r_tab;
int * Cbbtab = upsample->Cb_b_tab;
INT32 * Crgtab = upsample->Cr_g_tab;
INT32 * Cbgtab = upsample->Cb_g_tab;
JLONG * Crgtab = upsample->Cr_g_tab;
JLONG * Cbgtab = upsample->Cb_g_tab;
unsigned int r, g, b;
INT32 rgb;
JLONG rgb;
SHIFT_TEMPS
inptr00 = input_buf[0][in_row_group_ctr * 2];
@ -241,14 +242,14 @@ h2v2_merged_upsample_565_internal (j_decompress_ptr cinfo,
g = range_limit[y + cgreen];
b = range_limit[y + cblue];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr0 = rgb;
*(INT16*)outptr0 = (INT16)rgb;
y = GETJSAMPLE(*inptr01);
r = range_limit[y + cred];
g = range_limit[y + cgreen];
b = range_limit[y + cblue];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr1 = rgb;
*(INT16*)outptr1 = (INT16)rgb;
}
}
@ -270,12 +271,12 @@ h2v2_merged_upsample_565D_internal (j_decompress_ptr cinfo,
register JSAMPLE * range_limit = cinfo->sample_range_limit;
int * Crrtab = upsample->Cr_r_tab;
int * Cbbtab = upsample->Cb_b_tab;
INT32 * Crgtab = upsample->Cr_g_tab;
INT32 * Cbgtab = upsample->Cb_g_tab;
INT32 d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
INT32 d1 = dither_matrix[(cinfo->output_scanline+1) & DITHER_MASK];
JLONG * Crgtab = upsample->Cr_g_tab;
JLONG * Cbgtab = upsample->Cb_g_tab;
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
JLONG d1 = dither_matrix[(cinfo->output_scanline+1) & DITHER_MASK];
unsigned int r, g, b;
INT32 rgb;
JLONG rgb;
SHIFT_TEMPS
inptr00 = input_buf[0][in_row_group_ctr*2];
@ -343,13 +344,13 @@ h2v2_merged_upsample_565D_internal (j_decompress_ptr cinfo,
g = range_limit[DITHER_565_G(y + cgreen, d0)];
b = range_limit[DITHER_565_B(y + cblue, d0)];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr0 = rgb;
*(INT16*)outptr0 = (INT16)rgb;
y = GETJSAMPLE(*inptr01);
r = range_limit[DITHER_565_R(y + cred, d1)];
g = range_limit[DITHER_565_G(y + cgreen, d1)];
b = range_limit[DITHER_565_B(y + cblue, d1)];
rgb = PACK_SHORT_565(r, g, b);
*(INT16*)outptr1 = rgb;
*(INT16*)outptr1 = (INT16)rgb;
}
}

View File

@ -4,8 +4,9 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2011, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2011, 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains code for merged upsampling/color conversion.
*/
@ -35,8 +36,8 @@ h2v1_merged_upsample_internal (j_decompress_ptr cinfo,
register JSAMPLE * range_limit = cinfo->sample_range_limit;
int * Crrtab = upsample->Cr_r_tab;
int * Cbbtab = upsample->Cb_b_tab;
INT32 * Crgtab = upsample->Cr_g_tab;
INT32 * Cbgtab = upsample->Cb_g_tab;
JLONG * Crgtab = upsample->Cr_g_tab;
JLONG * Cbgtab = upsample->Cb_g_tab;
SHIFT_TEMPS
inptr0 = input_buf[0][in_row_group_ctr];
@ -108,8 +109,8 @@ h2v2_merged_upsample_internal (j_decompress_ptr cinfo,
register JSAMPLE * range_limit = cinfo->sample_range_limit;
int * Crrtab = upsample->Cr_r_tab;
int * Cbbtab = upsample->Cb_b_tab;
INT32 * Crgtab = upsample->Cr_g_tab;
INT32 * Cbgtab = upsample->Cb_g_tab;
JLONG * Crgtab = upsample->Cr_g_tab;
JLONG * Cbgtab = upsample->Cb_g_tab;
SHIFT_TEMPS
inptr00 = input_buf[0][in_row_group_ctr*2];

View File

@ -5,7 +5,8 @@
* Copyright (C) 1995-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2015, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains Huffman entropy decoding routines for progressive JPEG.
*
@ -68,12 +69,12 @@ typedef struct {
unsigned int restarts_to_go; /* MCUs left in this restart interval */
/* Pointers to derived tables (these workspaces have image lifespan) */
d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
d_derived_tbl *derived_tbls[NUM_HUFF_TBLS];
d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */
d_derived_tbl *ac_derived_tbl; /* active table during an AC scan */
} phuff_entropy_decoder;
typedef phuff_entropy_decoder * phuff_entropy_ptr;
typedef phuff_entropy_decoder *phuff_entropy_ptr;
/* Forward declarations */
METHODDEF(boolean) decode_mcu_DC_first (j_decompress_ptr cinfo,
@ -98,7 +99,7 @@ start_pass_phuff_decoder (j_decompress_ptr cinfo)
int ci, coefi, tbl;
d_derived_tbl **pdtbl;
int *coef_bit_ptr;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
is_DC_band = (cinfo->Ss == 0);
@ -297,8 +298,8 @@ decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
JBLOCKROW block;
BITREAD_STATE_VARS;
savable_state state;
d_derived_tbl * tbl;
jpeg_component_info * compptr;
d_derived_tbl *tbl;
jpeg_component_info *compptr;
/* Process restart marker if needed; may have to suspend */
if (cinfo->restart_interval) {
@ -368,7 +369,7 @@ decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
unsigned int EOBRUN;
JBLOCKROW block;
BITREAD_STATE_VARS;
d_derived_tbl * tbl;
d_derived_tbl *tbl;
/* Process restart marker if needed; may have to suspend */
if (cinfo->restart_interval) {
@ -504,7 +505,7 @@ decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
JBLOCKROW block;
JCOEFPTR thiscoef;
BITREAD_STATE_VARS;
d_derived_tbl * tbl;
d_derived_tbl *tbl;
int num_newnz;
int newnz_pos[DCTSIZE2];

View File

@ -5,7 +5,8 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* It was modified by The libjpeg-turbo Project to include only code relevant
* to libjpeg-turbo.
* For conditions of distribution and use, see the accompanying README file.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the decompression postprocessing controller.
* This controller manages the upsampling, color conversion, and color
@ -41,7 +42,7 @@ typedef struct {
JDIMENSION next_row; /* index of next row to fill/empty in strip */
} my_post_controller;
typedef my_post_controller * my_post_ptr;
typedef my_post_controller *my_post_ptr;
/* Forward declarations */

View File

@ -5,9 +5,11 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2010, D. R. Commander.
* Copyright (C) 2014, MIPS Technologies, Inc., California
* For conditions of distribution and use, see the accompanying README file.
* Copyright (C) 2010, 2015-2016, D. R. Commander.
* Copyright (C) 2014, MIPS Technologies, Inc., California.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains upsampling routines.
*
@ -22,51 +24,12 @@
* Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jdsample.h"
#include "jsimd.h"
#include "jpegcomp.h"
/* Pointer to routine to upsample a single component */
typedef void (*upsample1_ptr) (j_decompress_ptr cinfo,
jpeg_component_info * compptr,
JSAMPARRAY input_data,
JSAMPARRAY * output_data_ptr);
/* Private subobject */
typedef struct {
struct jpeg_upsampler pub; /* public fields */
/* Color conversion buffer. When using separate upsampling and color
* conversion steps, this buffer holds one upsampled row group until it
* has been color converted and output.
* Note: we do not allocate any storage for component(s) which are full-size,
* ie do not need rescaling. The corresponding entry of color_buf[] is
* simply set to point to the input data array, thereby avoiding copying.
*/
JSAMPARRAY color_buf[MAX_COMPONENTS];
/* Per-component upsampling method pointers */
upsample1_ptr methods[MAX_COMPONENTS];
int next_row_out; /* counts rows emitted from color_buf */
JDIMENSION rows_to_go; /* counts rows remaining in image */
/* Height of an input row group for each component. */
int rowgroup_height[MAX_COMPONENTS];
/* These arrays save pixel expansion factors so that int_expand need not
* recompute them each time. They are unused for other upsampling methods.
*/
UINT8 h_expand[MAX_COMPONENTS];
UINT8 v_expand[MAX_COMPONENTS];
} my_upsampler;
typedef my_upsampler * my_upsample_ptr;
/*
* Initialize for an upsampling pass.
@ -101,7 +64,7 @@ sep_upsample (j_decompress_ptr cinfo,
{
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
int ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
JDIMENSION num_rows;
/* Fill the conversion buffer, if it's empty */
@ -161,8 +124,8 @@ sep_upsample (j_decompress_ptr cinfo,
*/
METHODDEF(void)
fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
*output_data_ptr = input_data;
}
@ -174,8 +137,8 @@ fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
noop_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
*output_data_ptr = NULL; /* safety check */
}
@ -193,8 +156,8 @@ noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
int_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
JSAMPARRAY output_data = *output_data_ptr;
@ -237,8 +200,8 @@ int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
JSAMPARRAY output_data = *output_data_ptr;
register JSAMPROW inptr, outptr;
@ -265,8 +228,8 @@ h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
JSAMPARRAY output_data = *output_data_ptr;
register JSAMPROW inptr, outptr;
@ -308,8 +271,8 @@ h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
JSAMPARRAY output_data = *output_data_ptr;
register JSAMPROW inptr, outptr;
@ -349,15 +312,15 @@ h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
*/
METHODDEF(void)
h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
JSAMPARRAY output_data = *output_data_ptr;
register JSAMPROW inptr0, inptr1, outptr;
#if BITS_IN_JSAMPLE == 8
register int thiscolsum, lastcolsum, nextcolsum;
#else
register INT32 thiscolsum, lastcolsum, nextcolsum;
register JLONG thiscolsum, lastcolsum, nextcolsum;
#endif
register JDIMENSION colctr;
int inrow, outrow, v;
@ -407,17 +370,20 @@ jinit_upsampler (j_decompress_ptr cinfo)
{
my_upsample_ptr upsample;
int ci;
jpeg_component_info * compptr;
jpeg_component_info *compptr;
boolean need_buffer, do_fancy;
int h_in_group, v_in_group, h_out_group, v_out_group;
upsample = (my_upsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
sizeof(my_upsampler));
cinfo->upsample = (struct jpeg_upsampler *) upsample;
upsample->pub.start_pass = start_pass_upsample;
upsample->pub.upsample = sep_upsample;
upsample->pub.need_context_rows = FALSE; /* until we find out differently */
if (!cinfo->master->jinit_upsampler_no_alloc) {
upsample = (my_upsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
sizeof(my_upsampler));
cinfo->upsample = (struct jpeg_upsampler *) upsample;
upsample->pub.start_pass = start_pass_upsample;
upsample->pub.upsample = sep_upsample;
upsample->pub.need_context_rows = FALSE; /* until we find out differently */
} else
upsample = (my_upsample_ptr) cinfo->upsample;
if (cinfo->CCIR601_sampling) /* this isn't supported */
ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
@ -493,7 +459,7 @@ jinit_upsampler (j_decompress_ptr cinfo)
upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);
} else
ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
if (need_buffer) {
if (need_buffer && !cinfo->master->jinit_upsampler_no_alloc) {
upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
((j_common_ptr) cinfo, JPOOL_IMAGE,
(JDIMENSION) jround_up((long) cinfo->output_width,

Some files were not shown because too many files have changed in this diff Show More