зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team.
This commit is contained in:
Коммит
d53311459e
|
@ -12,7 +12,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
|
||||
|
@ -24,6 +24,7 @@
|
|||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
|
||||
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
|
||||
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="1342fd7b4b000ac3e76a5dfe111a0de9d710b4c8"/>
|
||||
<project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="1b26ad444462ccbd97f6319565b4735f7bd779e5"/>
|
||||
<project name="device/common" path="device/common" revision="4e1a38704dcfadef60ed2da3cfeba02a56b069d2"/>
|
||||
<project name="device/sample" path="device/sample" revision="b045905b46c8b4ee630d0c2aee7db63eaec722d9"/>
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="fa873799be5cf200f1d1d32a63953949c9dcdda8"/>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "c5f8db7e1e71a9bfe0d29665d2b4cf3ae773094e",
|
||||
"revision": "1150c11d1e6f0f78df3552dfca8c53d5ed5c173d",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>
|
||||
|
@ -24,6 +24,7 @@
|
|||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
|
||||
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
|
||||
<project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="1342fd7b4b000ac3e76a5dfe111a0de9d710b4c8"/>
|
||||
<project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="1b26ad444462ccbd97f6319565b4735f7bd779e5"/>
|
||||
<project name="device/common" path="device/common" revision="4e1a38704dcfadef60ed2da3cfeba02a56b069d2"/>
|
||||
<project name="device/sample" path="device/sample" revision="b045905b46c8b4ee630d0c2aee7db63eaec722d9"/>
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="fa873799be5cf200f1d1d32a63953949c9dcdda8"/>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="75ea7d07cdb590722634016410e12819faf82e5a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6586d2b8b43c6997be5cf5895bbdf3dd20490725"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -64,6 +64,7 @@ MOZ_PAY=1
|
|||
# Enable activities. These are used for FxOS developers currently.
|
||||
MOZ_ACTIVITIES=1
|
||||
MOZ_JSDOWNLOADS=1
|
||||
MOZ_WEBM_ENCODER=1
|
||||
# Enable exact rooting on desktop.
|
||||
JSGC_USE_EXACT_ROOTING=1
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ if CONFIG['MOZ_OPUS']:
|
|||
if CONFIG['MOZ_WEBM']:
|
||||
external_dirs += ['media/libnestegg']
|
||||
|
||||
if CONFIG['MOZ_WEBM_ENCODER']:
|
||||
external_dirs += ['media/libmkv']
|
||||
|
||||
if CONFIG['MOZ_VPX'] and not CONFIG['MOZ_NATIVE_LIBVPX']:
|
||||
external_dirs += ['media/libvpx']
|
||||
|
||||
|
|
|
@ -5546,6 +5546,11 @@ if test -n "$MOZ_OPUS"; then
|
|||
AC_DEFINE(MOZ_OPUS)
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_WEBM_ENCODER"; then
|
||||
AC_DEFINE(MOZ_WEBM_ENCODER)
|
||||
fi
|
||||
AC_SUBST(MOZ_WEBM_ENCODER)
|
||||
|
||||
dnl ==================================
|
||||
dnl = Check alsa availability on Linux
|
||||
dnl ==================================
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "nsPresContext.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsError.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
|
@ -863,6 +864,31 @@ HTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL,
|
|||
NS_FIRST_FORMSUBMIT_CATEGORY);
|
||||
}
|
||||
|
||||
// XXXbz what do the submit observers actually want? The window
|
||||
// of the document this is shown in? Or something else?
|
||||
// sXBL/XBL2 issue
|
||||
nsCOMPtr<nsPIDOMWindow> window = OwnerDoc()->GetWindow();
|
||||
|
||||
// Notify the secure browser UI, if any, that the form is being submitted.
|
||||
nsCOMPtr<nsIDocShell> docshell = OwnerDoc()->GetDocShell();
|
||||
if (docshell && !aEarlyNotify) {
|
||||
nsCOMPtr<nsISecureBrowserUI> secureUI;
|
||||
docshell->GetSecurityUI(getter_AddRefs(secureUI));
|
||||
nsCOMPtr<nsIFormSubmitObserver> formSubmitObserver =
|
||||
do_QueryInterface(secureUI);
|
||||
if (formSubmitObserver) {
|
||||
nsresult rv = formSubmitObserver->Notify(this,
|
||||
window,
|
||||
aActionURL,
|
||||
aCancelSubmit);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (*aCancelSubmit) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify observers that the form is being submitted.
|
||||
nsCOMPtr<nsIObserverService> service =
|
||||
mozilla::services::GetObserverService();
|
||||
|
@ -880,11 +906,6 @@ HTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL,
|
|||
nsCOMPtr<nsISupports> inst;
|
||||
*aCancelSubmit = false;
|
||||
|
||||
// XXXbz what do the submit observers actually want? The window
|
||||
// of the document this is shown in? Or something else?
|
||||
// sXBL/XBL2 issue
|
||||
nsCOMPtr<nsPIDOMWindow> window = OwnerDoc()->GetWindow();
|
||||
|
||||
bool loop = true;
|
||||
while (NS_SUCCEEDED(theEnum->HasMoreElements(&loop)) && loop) {
|
||||
theEnum->GetNext(getter_AddRefs(inst));
|
||||
|
|
|
@ -230,18 +230,20 @@ public:
|
|||
nsContentUtils::UnregisterShutdownObserver(this);
|
||||
}
|
||||
|
||||
void Pause()
|
||||
nsresult Pause()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread() && mTrackUnionStream);
|
||||
|
||||
NS_ENSURE_TRUE(NS_IsMainThread() && mTrackUnionStream, NS_ERROR_FAILURE);
|
||||
mTrackUnionStream->ChangeExplicitBlockerCount(-1);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Resume()
|
||||
nsresult Resume()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread() && mTrackUnionStream);
|
||||
|
||||
NS_ENSURE_TRUE(NS_IsMainThread() && mTrackUnionStream, NS_ERROR_FAILURE);
|
||||
mTrackUnionStream->ChangeExplicitBlockerCount(1);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMBlob> GetEncodedData()
|
||||
|
@ -499,11 +501,13 @@ MediaRecorder::Pause(ErrorResult& aResult)
|
|||
return;
|
||||
}
|
||||
|
||||
mState = RecordingState::Paused;
|
||||
|
||||
MOZ_ASSERT(mSession != nullptr);
|
||||
if (mSession) {
|
||||
mSession->Pause();
|
||||
nsresult rv = mSession->Pause();
|
||||
if (NS_FAILED(rv)) {
|
||||
NotifyError(rv);
|
||||
return;
|
||||
}
|
||||
mState = RecordingState::Paused;
|
||||
}
|
||||
}
|
||||
|
@ -518,7 +522,11 @@ MediaRecorder::Resume(ErrorResult& aResult)
|
|||
|
||||
MOZ_ASSERT(mSession != nullptr);
|
||||
if (mSession) {
|
||||
mSession->Resume();
|
||||
nsresult rv = mSession->Resume();
|
||||
if (NS_FAILED(rv)) {
|
||||
NotifyError(rv);
|
||||
return;
|
||||
}
|
||||
mState = RecordingState::Recording;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
#endif
|
||||
#ifdef MOZ_OPUS
|
||||
#include "OpusTrackEncoder.h"
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_VORBIS
|
||||
#include "VorbisTrackEncoder.h"
|
||||
#endif
|
||||
#ifdef MOZ_WEBM_ENCODER
|
||||
#include "VorbisTrackEncoder.h"
|
||||
|
|
|
@ -128,6 +128,20 @@ AudioTrackEncoder::InterleaveTrackData(AudioChunk& aChunk,
|
|||
}
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void
|
||||
AudioTrackEncoder::DeInterleaveTrackData(AudioDataValue* aInput,
|
||||
int32_t aDuration,
|
||||
int32_t aChannels,
|
||||
AudioDataValue* aOutput)
|
||||
{
|
||||
for (int32_t i = 0; i < aChannels; ++i) {
|
||||
for(int32_t j = 0; j < aDuration; ++j) {
|
||||
aOutput[i * aDuration + j] = aInput[i + j * aChannels];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VideoTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
|
||||
TrackID aID,
|
||||
|
|
|
@ -158,6 +158,13 @@ public:
|
|||
uint32_t aOutputChannels,
|
||||
AudioDataValue* aOutput);
|
||||
|
||||
/**
|
||||
* De-interleaves the aInput data and stores the result into aOutput.
|
||||
* No up-mix or down-mix operations inside.
|
||||
*/
|
||||
static void DeInterleaveTrackData(AudioDataValue* aInput, int32_t aDuration,
|
||||
int32_t aChannels, AudioDataValue* aOutput);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Number of samples per channel in a pcm buffer. This is also the value of
|
||||
|
|
|
@ -18,6 +18,7 @@ public:
|
|||
enum MetadataKind {
|
||||
METADATA_OPUS, // Represent the Opus metadata
|
||||
METADATA_VP8,
|
||||
METADATA_VORBIS,
|
||||
METADATA_AVC,
|
||||
METADATA_AAC,
|
||||
METADATA_UNKNOWN // Metadata Kind not set
|
||||
|
|
|
@ -0,0 +1,472 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* 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 "VP8TrackEncoder.h"
|
||||
#include "vpx/vp8cx.h"
|
||||
#include "vpx/vpx_encoder.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "prsystem.h"
|
||||
#include "WebMWriter.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gVP8TrackEncoderLog;
|
||||
#define VP8LOG(msg, ...) PR_LOG(gVP8TrackEncoderLog, PR_LOG_DEBUG, \
|
||||
(msg, ##__VA_ARGS__))
|
||||
// Debug logging macro with object pointer and class name.
|
||||
#else
|
||||
#define VP8LOG(msg, ...)
|
||||
#endif
|
||||
|
||||
#define DEFAULT_BITRATE 2500 // in kbit/s
|
||||
#define DEFAULT_ENCODE_FRAMERATE 30
|
||||
|
||||
VP8TrackEncoder::VP8TrackEncoder()
|
||||
: VideoTrackEncoder()
|
||||
, mEncodedFrameDuration(0)
|
||||
, mEncodedTimestamp(0)
|
||||
, mRemainingTicks(0)
|
||||
, mVPXContext(new vpx_codec_ctx_t())
|
||||
, mVPXImageWrapper(new vpx_image_t())
|
||||
{
|
||||
MOZ_COUNT_CTOR(VP8TrackEncoder);
|
||||
#ifdef PR_LOGGING
|
||||
if (!gVP8TrackEncoderLog) {
|
||||
gVP8TrackEncoderLog = PR_NewLogModule("VP8TrackEncoder");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
VP8TrackEncoder::~VP8TrackEncoder()
|
||||
{
|
||||
if (mInitialized) {
|
||||
vpx_codec_destroy(mVPXContext);
|
||||
}
|
||||
|
||||
if (mVPXImageWrapper) {
|
||||
vpx_img_free(mVPXImageWrapper);
|
||||
}
|
||||
MOZ_COUNT_DTOR(VP8TrackEncoder);
|
||||
}
|
||||
|
||||
nsresult
|
||||
VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, TrackRate aTrackRate)
|
||||
{
|
||||
if (aWidth < 1 || aHeight < 1 || aTrackRate <= 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
mTrackRate = aTrackRate;
|
||||
mEncodedFrameRate = DEFAULT_ENCODE_FRAMERATE;
|
||||
mEncodedFrameDuration = mTrackRate / mEncodedFrameRate;
|
||||
mFrameWidth = aWidth;
|
||||
mFrameHeight = aHeight;
|
||||
|
||||
// Encoder configuration structure.
|
||||
vpx_codec_enc_cfg_t config;
|
||||
memset(&config, 0, sizeof(vpx_codec_enc_cfg_t));
|
||||
if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config, 0)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Creating a wrapper to the image - setting image data to NULL. Actual
|
||||
// pointer will be set in encode. Setting align to 1, as it is meaningless
|
||||
// (actual memory is not allocated).
|
||||
vpx_img_wrap(mVPXImageWrapper, IMG_FMT_I420,
|
||||
mFrameWidth, mFrameHeight, 1, nullptr);
|
||||
|
||||
config.g_w = mFrameWidth;
|
||||
config.g_h = mFrameHeight;
|
||||
// TODO: Maybe we should have various aFrameRate bitrate pair for each devices?
|
||||
// or for different platform
|
||||
config.rc_target_bitrate = DEFAULT_BITRATE; // in kbit/s
|
||||
|
||||
// Setting the time base of the codec
|
||||
config.g_timebase.num = 1;
|
||||
config.g_timebase.den = mTrackRate;
|
||||
|
||||
config.g_error_resilient = 0;
|
||||
|
||||
config.g_lag_in_frames = 0; // 0- no frame lagging
|
||||
|
||||
int32_t number_of_cores = PR_GetNumberOfProcessors();
|
||||
if (mFrameWidth * mFrameHeight > 1280 * 960 && number_of_cores >= 6) {
|
||||
config.g_threads = 3; // 3 threads for 1080p.
|
||||
} else if (mFrameWidth * mFrameHeight > 640 * 480 && number_of_cores >= 3) {
|
||||
config.g_threads = 2; // 2 threads for qHD/HD.
|
||||
} else {
|
||||
config.g_threads = 1; // 1 thread for VGA or less
|
||||
}
|
||||
|
||||
// rate control settings
|
||||
config.rc_dropframe_thresh = 0;
|
||||
config.rc_end_usage = VPX_CBR;
|
||||
config.g_pass = VPX_RC_ONE_PASS;
|
||||
config.rc_resize_allowed = 1;
|
||||
config.rc_undershoot_pct = 100;
|
||||
config.rc_overshoot_pct = 15;
|
||||
config.rc_buf_initial_sz = 500;
|
||||
config.rc_buf_optimal_sz = 600;
|
||||
config.rc_buf_sz = 1000;
|
||||
|
||||
config.kf_mode = VPX_KF_AUTO;
|
||||
// Ensure that we can output one I-frame per second.
|
||||
config.kf_max_dist = mEncodedFrameRate;
|
||||
|
||||
vpx_codec_flags_t flags = 0;
|
||||
flags |= VPX_CODEC_USE_OUTPUT_PARTITION;
|
||||
if (vpx_codec_enc_init(mVPXContext, vpx_codec_vp8_cx(), &config, flags)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
vpx_codec_control(mVPXContext, VP8E_SET_STATIC_THRESHOLD, 1);
|
||||
vpx_codec_control(mVPXContext, VP8E_SET_CPUUSED, -6);
|
||||
vpx_codec_control(mVPXContext, VP8E_SET_TOKEN_PARTITIONS,
|
||||
VP8_ONE_TOKENPARTITION);
|
||||
|
||||
mInitialized = true;
|
||||
mon.NotifyAll();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<TrackMetadataBase>
|
||||
VP8TrackEncoder::GetMetadata()
|
||||
{
|
||||
{
|
||||
// Wait if mEncoder is not initialized.
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
while (!mCanceled && !mInitialized) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
if (mCanceled || mEncodingComplete) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<VP8Metadata> meta = new VP8Metadata();
|
||||
meta->mWidth = mFrameWidth;
|
||||
meta->mHeight = mFrameHeight;
|
||||
meta->mEncodedFrameRate = mEncodedFrameRate;
|
||||
|
||||
return meta.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
|
||||
{
|
||||
vpx_codec_iter_t iter = nullptr;
|
||||
EncodedFrame::FrameType frameType = EncodedFrame::P_FRAME;
|
||||
nsTArray<uint8_t> frameData;
|
||||
const vpx_codec_cx_pkt_t *pkt = nullptr;
|
||||
while ((pkt = vpx_codec_get_cx_data(mVPXContext, &iter)) != nullptr) {
|
||||
switch (pkt->kind) {
|
||||
case VPX_CODEC_CX_FRAME_PKT: {
|
||||
// Copy the encoded data from libvpx to frameData
|
||||
frameData.AppendElements((uint8_t*)pkt->data.frame.buf,
|
||||
pkt->data.frame.sz);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// End of frame
|
||||
if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) {
|
||||
if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
|
||||
frameType = EncodedFrame::I_FRAME;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!frameData.IsEmpty() &&
|
||||
(pkt->data.frame.pts == mEncodedTimestamp)) {
|
||||
// Copy the encoded data to aData.
|
||||
EncodedFrame* videoData = new EncodedFrame();
|
||||
videoData->SetFrameType(frameType);
|
||||
// Convert the timestamp and duration to Usecs.
|
||||
CheckedInt64 timestamp = FramesToUsecs(mEncodedTimestamp, mTrackRate);
|
||||
if (timestamp.isValid()) {
|
||||
videoData->SetTimeStamp(
|
||||
(uint64_t)FramesToUsecs(mEncodedTimestamp, mTrackRate).value());
|
||||
}
|
||||
CheckedInt64 duration = FramesToUsecs(pkt->data.frame.duration, mTrackRate);
|
||||
if (duration.isValid()) {
|
||||
videoData->SetDuration(
|
||||
(uint64_t)FramesToUsecs(pkt->data.frame.duration, mTrackRate).value());
|
||||
}
|
||||
videoData->SetFrameData(&frameData);
|
||||
VP8LOG("GetEncodedPartitions TimeStamp %lld Duration %lld\n",
|
||||
videoData->GetTimeStamp(), videoData->GetDuration());
|
||||
VP8LOG("frameType %d\n", videoData->GetFrameType());
|
||||
aData.AppendEncodedFrame(videoData);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void VP8TrackEncoder::PrepareMutedFrame()
|
||||
{
|
||||
if (mMuteFrame.IsEmpty()) {
|
||||
CreateMutedFrame(&mMuteFrame);
|
||||
}
|
||||
|
||||
uint32_t yPlanSize = mFrameWidth * mFrameHeight;
|
||||
uint32_t halfWidth = (mFrameWidth + 1) / 2;
|
||||
uint32_t halfHeight = (mFrameHeight + 1) / 2;
|
||||
uint32_t uvPlanSize = halfWidth * halfHeight;
|
||||
|
||||
MOZ_ASSERT(mMuteFrame.Length() >= (yPlanSize + uvPlanSize));
|
||||
uint8_t *y = mMuteFrame.Elements();
|
||||
uint8_t *cb = mMuteFrame.Elements() + yPlanSize;
|
||||
uint8_t *cr = mMuteFrame.Elements() + yPlanSize + uvPlanSize;
|
||||
|
||||
mVPXImageWrapper->planes[PLANE_Y] = y;
|
||||
mVPXImageWrapper->planes[PLANE_U] = cb;
|
||||
mVPXImageWrapper->planes[PLANE_V] = cr;
|
||||
mVPXImageWrapper->stride[VPX_PLANE_Y] = mFrameWidth;
|
||||
mVPXImageWrapper->stride[VPX_PLANE_U] = halfWidth;
|
||||
mVPXImageWrapper->stride[VPX_PLANE_V] = halfWidth;
|
||||
}
|
||||
|
||||
nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk)
|
||||
{
|
||||
if (aChunk.mFrame.GetForceBlack()) {
|
||||
PrepareMutedFrame();
|
||||
} else {
|
||||
layers::Image* img = aChunk.mFrame.GetImage();
|
||||
if (NS_WARN_IF(!img)) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
ImageFormat format = img->GetFormat();
|
||||
if (format != PLANAR_YCBCR) {
|
||||
VP8LOG("Unsupported video format\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Cast away constness b/c some of the accessors are non-const
|
||||
layers::PlanarYCbCrImage* yuv =
|
||||
const_cast<layers::PlanarYCbCrImage *>(static_cast<const layers::PlanarYCbCrImage *>(img));
|
||||
// Big-time assumption here that this is all contiguous data coming
|
||||
// from getUserMedia or other sources.
|
||||
MOZ_ASSERT(yuv);
|
||||
const layers::PlanarYCbCrImage::Data *data = yuv->GetData();
|
||||
|
||||
mVPXImageWrapper->planes[PLANE_Y] = data->mYChannel;
|
||||
mVPXImageWrapper->planes[PLANE_U] = data->mCbChannel;
|
||||
mVPXImageWrapper->planes[PLANE_V] = data->mCrChannel;
|
||||
mVPXImageWrapper->stride[VPX_PLANE_Y] = data->mYStride;
|
||||
mVPXImageWrapper->stride[VPX_PLANE_U] = data->mCbCrStride;
|
||||
mVPXImageWrapper->stride[VPX_PLANE_V] = data->mCbCrStride;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// These two define value used in GetNextEncodeOperation to determine the
|
||||
// EncodeOperation for next target frame.
|
||||
#define I_FRAME_RATIO (0.5)
|
||||
#define SKIP_FRAME_RATIO (0.75)
|
||||
|
||||
/**
|
||||
* Compares the elapsed time from the beginning of GetEncodedTrack and
|
||||
* the processed frame duration in mSourceSegment
|
||||
* in order to set the nextEncodeOperation for next target frame.
|
||||
*/
|
||||
VP8TrackEncoder::EncodeOperation
|
||||
VP8TrackEncoder::GetNextEncodeOperation(TimeDuration aTimeElapsed,
|
||||
TrackTicks aProcessedDuration)
|
||||
{
|
||||
int64_t durationInUsec =
|
||||
FramesToUsecs(aProcessedDuration + mEncodedFrameDuration,
|
||||
mTrackRate).value();
|
||||
if (aTimeElapsed.ToMicroseconds() > (durationInUsec * SKIP_FRAME_RATIO)) {
|
||||
// The encoder is too slow.
|
||||
// We should skip next frame to consume the mSourceSegment.
|
||||
return SKIP_FRAME;
|
||||
} else if (aTimeElapsed.ToMicroseconds() > (durationInUsec * I_FRAME_RATIO)) {
|
||||
// The encoder is a little slow.
|
||||
// We force the encoder to encode an I-frame to accelerate.
|
||||
return ENCODE_I_FRAME;
|
||||
} else {
|
||||
return ENCODE_NORMAL_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
TrackTicks
|
||||
VP8TrackEncoder::CalculateRemainingTicks(TrackTicks aDurationCopied,
|
||||
TrackTicks aEncodedDuration)
|
||||
{
|
||||
return mRemainingTicks + aEncodedDuration - aDurationCopied;
|
||||
}
|
||||
|
||||
// Try to extend the encodedDuration as long as possible if the target frame
|
||||
// has a long duration.
|
||||
TrackTicks
|
||||
VP8TrackEncoder::CalculateEncodedDuration(TrackTicks aDurationCopied)
|
||||
{
|
||||
TrackTicks temp64 = aDurationCopied;
|
||||
TrackTicks encodedDuration = mEncodedFrameDuration;
|
||||
temp64 -= mRemainingTicks;
|
||||
while (temp64 > mEncodedFrameDuration) {
|
||||
temp64 -= mEncodedFrameDuration;
|
||||
encodedDuration += mEncodedFrameDuration;
|
||||
}
|
||||
return encodedDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoding flow in GetEncodedTrack():
|
||||
* 1: Check the mInitialized state and the packet duration.
|
||||
* 2: Move the data from mRawSegment to mSourceSegment.
|
||||
* 3: Encode the video chunks in mSourceSegment in a for-loop.
|
||||
* 3.1: Pick the video chunk by mRemainingTicks.
|
||||
* 3.2: Calculate the encoding duration for the parameter of vpx_codec_encode().
|
||||
* The encoding duration is a multiple of mEncodedFrameDuration.
|
||||
* 3.3: Setup the video chunk to mVPXImageWrapper by PrepareRawFrame().
|
||||
* 3.4: Send frame into vp8 encoder by vpx_codec_encode().
|
||||
* 3.5: Get the output frame from encoder by calling GetEncodedPartitions().
|
||||
* 3.6: Calculate the mRemainingTicks for next target frame.
|
||||
* 3.7: Set the nextEncodeOperation for the next target frame.
|
||||
* There is a heuristic: If the frame duration we have processed in
|
||||
* mSourceSegment is 100ms, means that we can't spend more than 100ms to
|
||||
* encode it.
|
||||
* 4. Remove the encoded chunks in mSourceSegment after for-loop.
|
||||
*
|
||||
* Ex1: Input frame rate is 100 => input frame duration is 10ms for each.
|
||||
* mEncodedFrameRate is 30 => output frame duration is 33ms.
|
||||
* In this case, the frame duration in mSourceSegment will be:
|
||||
* 1st : 0~10ms
|
||||
* 2nd : 10~20ms
|
||||
* 3rd : 20~30ms
|
||||
* 4th : 30~40ms
|
||||
* ...
|
||||
* The VP8 encoder will take the 1st and 4th frames to encode. At beginning
|
||||
* mRemainingTicks is 0 for 1st frame, then the mRemainingTicks is set
|
||||
* to 23 to pick the 4th frame. (mEncodedFrameDuration - 1st frame duration)
|
||||
*
|
||||
* Ex2: Input frame rate is 25 => frame duration is 40ms for each.
|
||||
* mEncodedFrameRate is 30 => output frame duration is 33ms.
|
||||
* In this case, the frame duration in mSourceSegment will be:
|
||||
* 1st : 0~40ms
|
||||
* 2nd : 40~80ms
|
||||
* 3rd : 80~120ms
|
||||
* 4th : 120~160ms
|
||||
* ...
|
||||
* Because the input frame duration is 40ms larger than 33ms, so the first
|
||||
* encoded frame duration will be 66ms by calling CalculateEncodedDuration.
|
||||
* And the mRemainingTicks will be set to 26
|
||||
* (CalculateRemainingTicks 0+66-40) in order to pick the next frame(2nd)
|
||||
* in mSourceSegment.
|
||||
*/
|
||||
nsresult
|
||||
VP8TrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
{
|
||||
{
|
||||
// Move all the samples from mRawSegment to mSourceSegment. We only hold
|
||||
// the monitor in this block.
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
// Wait if mEncoder is not initialized, or when not enough raw data, but is
|
||||
// not the end of stream nor is being canceled.
|
||||
while (!mCanceled && (!mInitialized ||
|
||||
(mRawSegment.GetDuration() + mSourceSegment.GetDuration() <
|
||||
mEncodedFrameDuration && !mEndOfStream))) {
|
||||
mon.Wait();
|
||||
}
|
||||
if (mCanceled || mEncodingComplete) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mSourceSegment.AppendFrom(&mRawSegment);
|
||||
}
|
||||
|
||||
VideoSegment::ChunkIterator iter(mSourceSegment);
|
||||
TrackTicks durationCopied = 0;
|
||||
TrackTicks totalProcessedDuration = 0;
|
||||
TimeStamp timebase = TimeStamp::Now();
|
||||
EncodeOperation nextEncodeOperation = ENCODE_NORMAL_FRAME;
|
||||
|
||||
for (; !iter.IsEnded(); iter.Next()) {
|
||||
VideoChunk &chunk = *iter;
|
||||
// Accumulate chunk's duration to durationCopied until it reaches
|
||||
// mRemainingTicks.
|
||||
durationCopied += chunk.GetDuration();
|
||||
MOZ_ASSERT(mRemainingTicks <= mEncodedFrameDuration);
|
||||
VP8LOG("durationCopied %lld mRemainingTicks %lld\n",
|
||||
durationCopied, mRemainingTicks);
|
||||
if (durationCopied >= mRemainingTicks) {
|
||||
VP8LOG("nextEncodeOperation is %d\n",nextEncodeOperation);
|
||||
// Calculate encodedDuration for this target frame.
|
||||
TrackTicks encodedDuration = CalculateEncodedDuration(durationCopied);
|
||||
|
||||
// Encode frame.
|
||||
if (nextEncodeOperation != SKIP_FRAME) {
|
||||
nsresult rv = PrepareRawFrame(chunk);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||
|
||||
// Encode the data with VP8 encoder
|
||||
int flags = (nextEncodeOperation == ENCODE_NORMAL_FRAME) ?
|
||||
0 : VPX_EFLAG_FORCE_KF;
|
||||
if (vpx_codec_encode(mVPXContext, mVPXImageWrapper, mEncodedTimestamp,
|
||||
(unsigned long)encodedDuration, flags,
|
||||
VPX_DL_REALTIME)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Get the encoded data from VP8 encoder.
|
||||
GetEncodedPartitions(aData);
|
||||
} else {
|
||||
// SKIP_FRAME
|
||||
// Extend the duration of the last encoded data in aData
|
||||
// because this frame will be skip.
|
||||
nsRefPtr<EncodedFrame> last = nullptr;
|
||||
last = aData.GetEncodedFrames().LastElement();
|
||||
if (last) {
|
||||
last->SetDuration(last->GetDuration() + encodedDuration);
|
||||
}
|
||||
}
|
||||
// Move forward the mEncodedTimestamp.
|
||||
mEncodedTimestamp += encodedDuration;
|
||||
totalProcessedDuration += durationCopied;
|
||||
// Calculate mRemainingTicks for next target frame.
|
||||
mRemainingTicks = CalculateRemainingTicks(durationCopied,
|
||||
encodedDuration);
|
||||
|
||||
// Check the remain data is enough for next target frame.
|
||||
if (mSourceSegment.GetDuration() - totalProcessedDuration
|
||||
>= mEncodedFrameDuration) {
|
||||
TimeDuration elapsedTime = TimeStamp::Now() - timebase;
|
||||
nextEncodeOperation = GetNextEncodeOperation(elapsedTime,
|
||||
totalProcessedDuration);
|
||||
// Reset durationCopied for next iteration.
|
||||
durationCopied = 0;
|
||||
} else {
|
||||
// Process done, there is no enough data left for next iteration,
|
||||
// break the for-loop.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove the chunks we have processed.
|
||||
mSourceSegment.RemoveLeading(totalProcessedDuration);
|
||||
VP8LOG("RemoveLeading %lld\n",totalProcessedDuration);
|
||||
|
||||
// End of stream, pull the rest frames in encoder.
|
||||
if (mEndOfStream) {
|
||||
VP8LOG("mEndOfStream is true\n");
|
||||
mEncodingComplete = true;
|
||||
if (vpx_codec_encode(mVPXContext, nullptr, mEncodedTimestamp,
|
||||
mEncodedFrameDuration, 0, VPX_DL_REALTIME)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
GetEncodedPartitions(aData);
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* 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/. */
|
||||
|
||||
#ifndef VP8TrackEncoder_h_
|
||||
#define VP8TrackEncoder_h_
|
||||
|
||||
#include "TrackEncoder.h"
|
||||
#include "vpx/vpx_codec.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
typedef struct vpx_codec_ctx vpx_codec_ctx_t;
|
||||
typedef struct vpx_codec_enc_cfg vpx_codec_enc_cfg_t;
|
||||
typedef struct vpx_image vpx_image_t;
|
||||
|
||||
/**
|
||||
* VP8TrackEncoder implements VideoTrackEncoder by using libvpx library.
|
||||
* We implement a realtime and fixed FPS encoder. In order to achieve that,
|
||||
* there is a pick target frame and drop frame encoding policy implemented in
|
||||
* GetEncodedTrack.
|
||||
*/
|
||||
class VP8TrackEncoder : public VideoTrackEncoder
|
||||
{
|
||||
enum EncodeOperation {
|
||||
ENCODE_NORMAL_FRAME, // VP8 track encoder works normally.
|
||||
ENCODE_I_FRAME, // The next frame will be encoded as I-Frame.
|
||||
SKIP_FRAME, // Skip the next frame.
|
||||
};
|
||||
public:
|
||||
VP8TrackEncoder();
|
||||
virtual ~VP8TrackEncoder();
|
||||
|
||||
already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
||||
nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
nsresult Init(int32_t aWidth, int32_t aHeight,
|
||||
TrackRate aTrackRate) MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// Calculate the target frame's encoded duration.
|
||||
TrackTicks CalculateEncodedDuration(TrackTicks aDurationCopied);
|
||||
|
||||
// Calculate the mRemainingTicks for next target frame.
|
||||
TrackTicks CalculateRemainingTicks(TrackTicks aDurationCopied,
|
||||
TrackTicks aEncodedDuration);
|
||||
|
||||
// Get the EncodeOperation for next target frame.
|
||||
EncodeOperation GetNextEncodeOperation(TimeDuration aTimeElapsed,
|
||||
TrackTicks aProcessedDuration);
|
||||
|
||||
// Get the encoded data from encoder to aData.
|
||||
nsresult GetEncodedPartitions(EncodedFrameContainer& aData);
|
||||
|
||||
// Prepare the input data to the mVPXImageWrapper for encoding.
|
||||
nsresult PrepareRawFrame(VideoChunk &aChunk);
|
||||
|
||||
// Prepare the muted frame data to the mVPXImageWrapper for encoding.
|
||||
void PrepareMutedFrame();
|
||||
|
||||
// Output frame rate.
|
||||
uint32_t mEncodedFrameRate;
|
||||
// Duration for the output frame, reciprocal to mEncodedFrameRate.
|
||||
TrackTicks mEncodedFrameDuration;
|
||||
// Encoded timestamp.
|
||||
TrackTicks mEncodedTimestamp;
|
||||
// Duration to the next encode frame.
|
||||
TrackTicks mRemainingTicks;
|
||||
|
||||
// Muted frame, we only create it once.
|
||||
nsTArray<uint8_t> mMuteFrame;
|
||||
|
||||
/**
|
||||
* A local segment queue which takes the raw data out from mRawSegment in the
|
||||
* call of GetEncodedTrack(). Since we implement the fixed FPS encoding
|
||||
* policy, it needs to be global in order to store the leftover segments
|
||||
* taken from mRawSegment.
|
||||
*/
|
||||
VideoSegment mSourceSegment;
|
||||
|
||||
// VP8 relative members.
|
||||
// Codec context structure.
|
||||
nsAutoPtr<vpx_codec_ctx_t> mVPXContext;
|
||||
// Image Descriptor.
|
||||
nsAutoPtr<vpx_image_t> mVPXImageWrapper;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -0,0 +1,238 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* 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 "VorbisTrackEncoder.h"
|
||||
#include <ogg/ogg.h>
|
||||
#include <vorbis/vorbisenc.h>
|
||||
#include "WebMWriter.h"
|
||||
|
||||
// One actually used: Encoding using a VBR quality mode. The usable range is -.1
|
||||
// (lowest quality, smallest file) to 1. (highest quality, largest file).
|
||||
// Example quality mode .4: 44kHz stereo coupled, roughly 128kbps VBR
|
||||
// ret = vorbis_encode_init_vbr(&vi,2,44100,.4);
|
||||
static const float BASE_QUALITY = 0.4f;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#undef LOG
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo* gVorbisTrackEncoderLog;
|
||||
#define VORBISLOG(msg, ...) PR_LOG(gVorbisTrackEncoderLog, PR_LOG_DEBUG, \
|
||||
(msg, ##__VA_ARGS__))
|
||||
#else
|
||||
#define VORBISLOG(msg, ...)
|
||||
#endif
|
||||
|
||||
VorbisTrackEncoder::VorbisTrackEncoder()
|
||||
: AudioTrackEncoder()
|
||||
{
|
||||
MOZ_COUNT_CTOR(VorbisTrackEncoder);
|
||||
#ifdef PR_LOGGING
|
||||
if (!gVorbisTrackEncoderLog) {
|
||||
gVorbisTrackEncoderLog = PR_NewLogModule("VorbisTrackEncoder");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
VorbisTrackEncoder::~VorbisTrackEncoder()
|
||||
{
|
||||
MOZ_COUNT_DTOR(VorbisTrackEncoder);
|
||||
if (mInitialized) {
|
||||
vorbis_block_clear(&mVorbisBlock);
|
||||
vorbis_dsp_clear(&mVorbisDsp);
|
||||
vorbis_info_clear(&mVorbisInfo);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
VorbisTrackEncoder::Init(int aChannels, int aSamplingRate)
|
||||
{
|
||||
if (aChannels <= 0 || aChannels > 8) {
|
||||
VORBISLOG("aChannels <= 0 || aChannels > 8");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// This monitor is used to wake up other methods that are waiting for encoder
|
||||
// to be completely initialized.
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
mChannels = aChannels;
|
||||
mSamplingRate = aSamplingRate;
|
||||
|
||||
int ret = 0;
|
||||
vorbis_info_init(&mVorbisInfo);
|
||||
|
||||
ret = vorbis_encode_init_vbr(&mVorbisInfo, mChannels, mSamplingRate,
|
||||
BASE_QUALITY);
|
||||
|
||||
mInitialized = (ret == 0);
|
||||
|
||||
if (mInitialized) {
|
||||
// Set up the analysis state and auxiliary encoding storage
|
||||
vorbis_analysis_init(&mVorbisDsp, &mVorbisInfo);
|
||||
vorbis_block_init(&mVorbisDsp, &mVorbisBlock);
|
||||
}
|
||||
|
||||
mon.NotifyAll();
|
||||
|
||||
return ret == 0 ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void VorbisTrackEncoder::WriteLacing(nsTArray<uint8_t> *aOutput, int32_t aLacing)
|
||||
{
|
||||
while (aLacing > 255) {
|
||||
aLacing -= 255;
|
||||
aOutput->AppendElement(255);
|
||||
}
|
||||
aOutput->AppendElement((uint8_t)aLacing);
|
||||
}
|
||||
|
||||
already_AddRefed<TrackMetadataBase>
|
||||
VorbisTrackEncoder::GetMetadata()
|
||||
{
|
||||
{
|
||||
// Wait if encoder is not initialized.
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
while (!mCanceled && !mInitialized) {
|
||||
mon.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
if (mCanceled || mEncodingComplete) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Vorbis codec specific data
|
||||
// http://matroska.org/technical/specs/codecid/index.html
|
||||
nsRefPtr<VorbisMetadata> meta = new VorbisMetadata();
|
||||
meta->mBitDepth = 32; // float for desktop
|
||||
meta->mChannels = mChannels;
|
||||
meta->mSamplingFrequency = mSamplingRate;
|
||||
ogg_packet header;
|
||||
ogg_packet header_comm;
|
||||
ogg_packet header_code;
|
||||
// Add comment
|
||||
vorbis_comment vorbisComment;
|
||||
vorbis_comment_init(&vorbisComment);
|
||||
vorbis_comment_add_tag(&vorbisComment, "ENCODER",
|
||||
NS_LITERAL_CSTRING("Mozilla VorbisTrackEncoder " MOZ_APP_UA_VERSION).get());
|
||||
vorbis_analysis_headerout(&mVorbisDsp, &vorbisComment,
|
||||
&header,&header_comm, &header_code);
|
||||
vorbis_comment_clear(&vorbisComment);
|
||||
// number of distinct packets - 1
|
||||
meta->mData.AppendElement(2);
|
||||
// Xiph-style lacing header.bytes, header_comm.bytes
|
||||
WriteLacing(&(meta->mData), header.bytes);
|
||||
WriteLacing(&(meta->mData), header_comm.bytes);
|
||||
|
||||
// Append the three packets
|
||||
meta->mData.AppendElements(header.packet, header.bytes);
|
||||
meta->mData.AppendElements(header_comm.packet, header_comm.bytes);
|
||||
meta->mData.AppendElements(header_code.packet, header_code.bytes);
|
||||
|
||||
return meta.forget();
|
||||
}
|
||||
|
||||
void
|
||||
VorbisTrackEncoder::GetEncodedFrames(EncodedFrameContainer& aData)
|
||||
{
|
||||
// vorbis does some data preanalysis, then divvies up blocks for
|
||||
// more involved (potentially parallel) processing. Get a single
|
||||
// block for encoding now.
|
||||
while (vorbis_analysis_blockout(&mVorbisDsp, &mVorbisBlock) == 1) {
|
||||
ogg_packet oggPacket;
|
||||
if (vorbis_analysis(&mVorbisBlock, &oggPacket) == 0) {
|
||||
VORBISLOG("vorbis_analysis_blockout block size %d", oggPacket.bytes);
|
||||
EncodedFrame* audiodata = new EncodedFrame();
|
||||
audiodata->SetFrameType(EncodedFrame::AUDIO_FRAME);
|
||||
nsTArray<uint8_t> frameData;
|
||||
frameData.AppendElements(oggPacket.packet, oggPacket.bytes);
|
||||
audiodata->SetFrameData(&frameData);
|
||||
aData.AppendEncodedFrame(audiodata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
VorbisTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
|
||||
{
|
||||
if (mEosSetInEncoder) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoPtr<AudioSegment> sourceSegment;
|
||||
sourceSegment = new AudioSegment();
|
||||
{
|
||||
// Move all the samples from mRawSegment to sourceSegment. We only hold
|
||||
// the monitor in this block.
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
// Wait if mEncoder is not initialized, or when not enough raw data, but is
|
||||
// not the end of stream nor is being canceled.
|
||||
while (!mCanceled && mRawSegment.GetDuration() < GetPacketDuration() &&
|
||||
!mEndOfStream) {
|
||||
mon.Wait();
|
||||
}
|
||||
VORBISLOG("GetEncodedTrack passes wait, duration is %lld\n",
|
||||
mRawSegment.GetDuration());
|
||||
if (mCanceled || mEncodingComplete) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
sourceSegment->AppendFrom(&mRawSegment);
|
||||
}
|
||||
|
||||
if (mEndOfStream && (sourceSegment->GetDuration() == 0)
|
||||
&& !mEosSetInEncoder) {
|
||||
mEncodingComplete = true;
|
||||
mEosSetInEncoder = true;
|
||||
VORBISLOG("[Vorbis] Done encoding.");
|
||||
vorbis_analysis_wrote(&mVorbisDsp, 0);
|
||||
GetEncodedFrames(aData);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Start encoding data.
|
||||
AudioSegment::ChunkIterator iter(*sourceSegment);
|
||||
|
||||
AudioDataValue **vorbisBuffer =
|
||||
vorbis_analysis_buffer(&mVorbisDsp, (int)sourceSegment->GetDuration());
|
||||
|
||||
int framesCopied = 0;
|
||||
nsAutoTArray<AudioDataValue, 9600> interleavedPcm;
|
||||
nsAutoTArray<AudioDataValue, 9600> nonInterleavedPcm;
|
||||
interleavedPcm.SetLength(sourceSegment->GetDuration() * mChannels);
|
||||
nonInterleavedPcm.SetLength(sourceSegment->GetDuration() * mChannels);
|
||||
while (!iter.IsEnded()) {
|
||||
AudioChunk chunk = *iter;
|
||||
int frameToCopy = chunk.GetDuration();
|
||||
if (!chunk.IsNull()) {
|
||||
InterleaveTrackData(chunk, frameToCopy, mChannels,
|
||||
interleavedPcm.Elements() + framesCopied * mChannels);
|
||||
} else { // empty data
|
||||
memset(interleavedPcm.Elements() + framesCopied * mChannels, 0,
|
||||
frameToCopy * mChannels * sizeof(AudioDataValue));
|
||||
}
|
||||
framesCopied += frameToCopy;
|
||||
iter.Next();
|
||||
}
|
||||
// De-interleave the interleavedPcm.
|
||||
DeInterleaveTrackData(interleavedPcm.Elements(), framesCopied, mChannels,
|
||||
nonInterleavedPcm.Elements());
|
||||
// Copy the nonInterleavedPcm to vorbis buffer.
|
||||
for(uint8_t i = 0; i < mChannels; ++i) {
|
||||
memcpy(vorbisBuffer[i], nonInterleavedPcm.Elements() + framesCopied * i,
|
||||
framesCopied * sizeof(AudioDataValue));
|
||||
}
|
||||
|
||||
// Now the vorbisBuffer contain the all data in non-interleaved.
|
||||
// Tell the library how much we actually submitted.
|
||||
vorbis_analysis_wrote(&mVorbisDsp, framesCopied);
|
||||
VORBISLOG("vorbis_analysis_wrote framesCopied %d\n", framesCopied);
|
||||
GetEncodedFrames(aData);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* 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/. */
|
||||
|
||||
#ifndef VorbisTrackEncoder_h_
|
||||
#define VorbisTrackEncoder_h_
|
||||
|
||||
#include "TrackEncoder.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class VorbisTrackEncoder : public AudioTrackEncoder
|
||||
{
|
||||
public:
|
||||
VorbisTrackEncoder();
|
||||
virtual ~VorbisTrackEncoder();
|
||||
|
||||
already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
||||
nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* http://xiph.org/vorbis/doc/libvorbis/vorbis_analysis_buffer.html
|
||||
* We use 1024 samples for the write buffer; libvorbis will construct packets
|
||||
* with the appropriate duration for the encoding mode internally.
|
||||
*/
|
||||
int GetPacketDuration() MOZ_FINAL MOZ_OVERRIDE {
|
||||
return 1024;
|
||||
}
|
||||
|
||||
nsresult Init(int aChannels, int aSamplingRate) MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// Write Xiph-style lacing to aOutput.
|
||||
void WriteLacing(nsTArray<uint8_t> *aOutput, int32_t aLacing);
|
||||
|
||||
// Get the encoded data from vorbis encoder and append into aData.
|
||||
void GetEncodedFrames(EncodedFrameContainer& aData);
|
||||
|
||||
// vorbis codec members
|
||||
// Struct that stores all the static vorbis bitstream settings.
|
||||
vorbis_info mVorbisInfo;
|
||||
// Central working state for the PCM->packet encoder.
|
||||
vorbis_dsp_state mVorbisDsp;
|
||||
// Local working space for PCM->packet encode.
|
||||
vorbis_block mVorbisBlock;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
|
@ -20,13 +20,21 @@ UNIFIED_SOURCES += [
|
|||
'TrackEncoder.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_OMX_ENCODER']:
|
||||
EXPORTS += ['OmxTrackEncoder.h']
|
||||
UNIFIED_SOURCES += ['OmxTrackEncoder.cpp']
|
||||
|
||||
if CONFIG['MOZ_OPUS']:
|
||||
EXPORTS += ['OpusTrackEncoder.h']
|
||||
UNIFIED_SOURCES += ['OpusTrackEncoder.cpp']
|
||||
|
||||
if CONFIG['MOZ_OMX_ENCODER']:
|
||||
EXPORTS += ['OmxTrackEncoder.h']
|
||||
UNIFIED_SOURCES += ['OmxTrackEncoder.cpp']
|
||||
if CONFIG['MOZ_WEBM_ENCODER']:
|
||||
EXPORTS += ['VorbisTrackEncoder.h',
|
||||
'VP8TrackEncoder.h',
|
||||
]
|
||||
UNIFIED_SOURCES += ['VorbisTrackEncoder.cpp',
|
||||
'VP8TrackEncoder.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
|
|
|
@ -256,6 +256,7 @@ support-files =
|
|||
[test_mediarecorder_reload_crash.html]
|
||||
[test_mediarecorder_record_immediate_stop.html]
|
||||
[test_mediarecorder_record_session.html]
|
||||
[test_mediarecorder_unsupported_src.html]
|
||||
[test_playback.html]
|
||||
[test_seekLies.html]
|
||||
[test_media_sniffer.html]
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Bug 957439 - Media Recording - Assertion fail at Pause if unsupported input stream.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=957439">Mozilla Bug 957439</a>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function startTest() {
|
||||
navigator.mozGetUserMedia({audio: false, video: true, fake: true},
|
||||
function(stream) {
|
||||
|
||||
// Expected callback sequence should be:
|
||||
// 1. onerror (from start)
|
||||
// 2. onerror (from pause)
|
||||
// 3. ondataavailable
|
||||
// 4. onstop
|
||||
var callbackStep = 0;
|
||||
var mediaRecorder = new MediaRecorder(stream);
|
||||
|
||||
is(mediaRecorder.stream, stream, 'Stream should be provided on creation');
|
||||
|
||||
mediaRecorder.onerror = function (e) {
|
||||
callbackStep++;
|
||||
ok(callbackStep < 3, 'onerror callback fired as expected.');
|
||||
is(e.name, 'GenericError', 'Error name should be GenericError.');
|
||||
is(mediaRecorder.mimeType, '', 'mimetype should be empty');
|
||||
is(mediaRecorder.state, 'recording', 'state is recording');
|
||||
info('onerror callback fired');
|
||||
}
|
||||
|
||||
mediaRecorder.onwarning = function () {
|
||||
ok(false, 'Unexpected onwarning callback fired.');
|
||||
};
|
||||
|
||||
mediaRecorder.ondataavailable = function (evt) {
|
||||
callbackStep++;
|
||||
info('ondataavailable callback fired');
|
||||
is(callbackStep, 3, 'should fired ondataavailable callback');
|
||||
is(evt.data.size, 0, 'data size should be zero');
|
||||
ok(evt instanceof BlobEvent,
|
||||
'Events fired from ondataavailable should be BlobEvent');
|
||||
is(evt.data.type, '', 'encoder start fail, blob miemType should be empty');
|
||||
};
|
||||
|
||||
mediaRecorder.onstop = function() {
|
||||
callbackStep++;
|
||||
info('onstop callback fired');
|
||||
is(mediaRecorder.state, 'inactive', 'state should be inactive');
|
||||
is(callbackStep, 4, 'should fired onstop callback');
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
try {
|
||||
mediaRecorder.start();
|
||||
} catch(e) {
|
||||
ok(false, 'Should not get exception in start call.');
|
||||
}
|
||||
|
||||
try {
|
||||
mediaRecorder.pause();
|
||||
} catch(e) {
|
||||
ok(false, 'Should not get exception in pause call.');
|
||||
}
|
||||
},
|
||||
function(err) {
|
||||
ok(false, 'Unexpected error fired with: ' + err);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// In order to generate an "unsupported stream", pref off video encoding to
|
||||
// make the platform support audio encoding only.
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{
|
||||
"set": [
|
||||
["media.encoder.webm.enabled", false]
|
||||
]
|
||||
}, startTest);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
|
@ -0,0 +1,177 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* 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 "EbmlComposer.h"
|
||||
#include "libmkv/EbmlIDs.h"
|
||||
#include "libmkv/EbmlWriter.h"
|
||||
#include "libmkv/WebMElement.h"
|
||||
#include "prtime.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Timecode scale in nanoseconds
|
||||
static const unsigned long TIME_CODE_SCALE = 1000000;
|
||||
// The WebM header size without audio CodecPrivateData
|
||||
static const int32_t DEFAULT_HEADER_SIZE = 1024;
|
||||
|
||||
void EbmlComposer::GenerateHeader()
|
||||
{
|
||||
// Write the EBML header.
|
||||
EbmlGlobal ebml;
|
||||
// The WEbM header default size usually smaller than 1k.
|
||||
nsAutoArrayPtr<uint8_t> buffer(new uint8_t[DEFAULT_HEADER_SIZE +
|
||||
mCodecPrivateData.Length()]);
|
||||
ebml.buf = buffer.get();
|
||||
ebml.offset = 0;
|
||||
writeHeader(&ebml);
|
||||
{
|
||||
EbmlLoc segEbmlLoc, ebmlLocseg, ebmlLoc;
|
||||
Ebml_StartSubElement(&ebml, &segEbmlLoc, Segment);
|
||||
{
|
||||
Ebml_StartSubElement(&ebml, &ebmlLocseg, SeekHead);
|
||||
// Todo: We don't know the exact sizes of encoded data and ignore this section.
|
||||
Ebml_EndSubElement(&ebml, &ebmlLocseg);
|
||||
writeSegmentInformation(&ebml, &ebmlLoc, TIME_CODE_SCALE, 0);
|
||||
{
|
||||
EbmlLoc trackLoc;
|
||||
Ebml_StartSubElement(&ebml, &trackLoc, Tracks);
|
||||
{
|
||||
char cid_string[8];
|
||||
// Video
|
||||
if (mWidth > 0 && mHeight > 0) {
|
||||
strcpy(cid_string, "V_VP8");
|
||||
writeVideoTrack(&ebml, 0x1, 0, cid_string,
|
||||
mWidth, mHeight, mFrameRate);
|
||||
}
|
||||
// Audio
|
||||
if (mCodecPrivateData.Length() > 0) {
|
||||
strcpy(cid_string, "A_VORBIS");
|
||||
writeAudioTrack(&ebml, 0x2, 0x0, cid_string, mSampleFreq,
|
||||
mChannels, mCodecPrivateData.Elements(),
|
||||
mCodecPrivateData.Length());
|
||||
}
|
||||
}
|
||||
Ebml_EndSubElement(&ebml, &trackLoc);
|
||||
}
|
||||
}
|
||||
// The Recording length is unknow and ignore write the whole Segment element size
|
||||
}
|
||||
MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(),
|
||||
"write more data > EBML_BUFFER_SIZE");
|
||||
mClusterBuffs.AppendElement();
|
||||
mClusterBuffs.LastElement().SetLength(ebml.offset);
|
||||
memcpy(mClusterBuffs.LastElement().Elements(), ebml.buf, ebml.offset);
|
||||
}
|
||||
|
||||
void EbmlComposer::FinishCluster()
|
||||
{
|
||||
MOZ_ASSERT(mClusterLengthLoc > 0 );
|
||||
MOZ_ASSERT(mClusterHeaderIndex > 0);
|
||||
for (uint32_t i = 0; i < mClusterBuffs.Length(); i ++ ) {
|
||||
mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]);
|
||||
}
|
||||
mClusterBuffs.Clear();
|
||||
EbmlGlobal ebml;
|
||||
EbmlLoc ebmlLoc;
|
||||
ebmlLoc.offset = mClusterLengthLoc;
|
||||
ebml.offset = mClusterCanFlushBuffs[mClusterHeaderIndex].Length();
|
||||
ebml.buf = mClusterCanFlushBuffs[mClusterHeaderIndex].Elements();
|
||||
Ebml_EndSubElement(&ebml, &ebmlLoc);
|
||||
mClusterHeaderIndex = 0;
|
||||
mClusterLengthLoc = 0;
|
||||
}
|
||||
|
||||
void
|
||||
EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame)
|
||||
{
|
||||
EbmlGlobal ebml;
|
||||
ebml.offset = 0;
|
||||
|
||||
if (aFrame->GetFrameType() == EncodedFrame::FrameType::I_FRAME && mClusterHeaderIndex > 0) {
|
||||
FinishCluster();
|
||||
}
|
||||
|
||||
mClusterBuffs.AppendElement();
|
||||
mClusterBuffs.LastElement().SetLength(aFrame->GetFrameData().Length() + DEFAULT_HEADER_SIZE);
|
||||
ebml.buf = mClusterBuffs.LastElement().Elements();
|
||||
|
||||
if (aFrame->GetFrameType() == EncodedFrame::FrameType::I_FRAME) {
|
||||
EbmlLoc ebmlLoc;
|
||||
Ebml_StartSubElement(&ebml, &ebmlLoc, Cluster);
|
||||
mClusterHeaderIndex = mClusterBuffs.Length() - 1; // current cluster header array index
|
||||
mClusterLengthLoc = ebmlLoc.offset;
|
||||
if (aFrame->GetFrameType() != EncodedFrame::FrameType::AUDIO_FRAME) {
|
||||
mClusterTimecode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC;
|
||||
}
|
||||
Ebml_SerializeUnsigned(&ebml, Timecode, mClusterTimecode);
|
||||
}
|
||||
|
||||
if (aFrame->GetFrameType() != EncodedFrame::FrameType::AUDIO_FRAME) {
|
||||
short timeCode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC - mClusterTimecode;
|
||||
writeSimpleBlock(&ebml, 0x1, timeCode, aFrame->GetFrameType() ==
|
||||
EncodedFrame::FrameType::I_FRAME,
|
||||
0, 0, (unsigned char*)aFrame->GetFrameData().Elements(),
|
||||
aFrame->GetFrameData().Length());
|
||||
} else {
|
||||
writeSimpleBlock(&ebml, 0x2, 0, false,
|
||||
0, 0, (unsigned char*)aFrame->GetFrameData().Elements(),
|
||||
aFrame->GetFrameData().Length());
|
||||
}
|
||||
MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(),
|
||||
"write more data > EBML_BUFFER_SIZE");
|
||||
mClusterBuffs.LastElement().SetLength(ebml.offset);
|
||||
}
|
||||
|
||||
void
|
||||
EbmlComposer::SetVideoConfig(uint32_t aWidth, uint32_t aHeight,
|
||||
float aFrameRate)
|
||||
{
|
||||
MOZ_ASSERT(aWidth > 0, "Width should > 0");
|
||||
MOZ_ASSERT(aHeight > 0, "Height should > 0");
|
||||
MOZ_ASSERT(aFrameRate > 0, "FrameRate should > 0");
|
||||
mWidth = aWidth;
|
||||
mHeight = aHeight;
|
||||
mFrameRate = aFrameRate;
|
||||
}
|
||||
|
||||
void
|
||||
EbmlComposer::SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels,
|
||||
uint32_t aBitDepth)
|
||||
{
|
||||
MOZ_ASSERT(aSampleFreq > 0, "SampleFreq should > 0");
|
||||
MOZ_ASSERT(aBitDepth > 0, "BitDepth should > 0");
|
||||
MOZ_ASSERT(aChannels > 0, "Channels should > 0");
|
||||
mSampleFreq = aSampleFreq;
|
||||
mBitDepth = aBitDepth;
|
||||
mChannels = aChannels;
|
||||
}
|
||||
|
||||
void
|
||||
EbmlComposer::ExtractBuffer(nsTArray<nsTArray<uint8_t> >* aDestBufs,
|
||||
uint32_t aFlag)
|
||||
{
|
||||
if ((aFlag & ContainerWriter::FLUSH_NEEDED) && mClusterHeaderIndex > 0) {
|
||||
FinishCluster();
|
||||
}
|
||||
// aDestBufs may have some element
|
||||
for (uint32_t i = 0; i < mClusterCanFlushBuffs.Length(); i ++ ) {
|
||||
aDestBufs->AppendElement()->SwapElements(mClusterCanFlushBuffs[i]);
|
||||
}
|
||||
mClusterCanFlushBuffs.Clear();
|
||||
}
|
||||
|
||||
EbmlComposer::EbmlComposer()
|
||||
: mClusterHeaderIndex(0)
|
||||
, mClusterLengthLoc(0)
|
||||
, mClusterTimecode(0)
|
||||
, mWidth(0)
|
||||
, mHeight(0)
|
||||
, mFrameRate(0)
|
||||
, mSampleFreq(0)
|
||||
, mBitDepth(0)
|
||||
, mChannels(0)
|
||||
{}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* 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/. */
|
||||
|
||||
#ifndef EbmlComposer_h_
|
||||
#define EbmlComposer_h_
|
||||
#include "nsTArray.h"
|
||||
#include "ContainerWriter.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* A WebM muxer helper for package the valid WebM format.
|
||||
*/
|
||||
class EbmlComposer {
|
||||
public:
|
||||
EbmlComposer();
|
||||
/*
|
||||
* Assign the parameter which header required.
|
||||
*/
|
||||
void SetVideoConfig(uint32_t aWidth, uint32_t aHeight, float aFrameRate);
|
||||
|
||||
void SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels,
|
||||
uint32_t bitDepth);
|
||||
/*
|
||||
* Set the CodecPrivateData for writing in header.
|
||||
*/
|
||||
void SetAudioCodecPrivateData(nsTArray<uint8_t>& aBufs)
|
||||
{
|
||||
mCodecPrivateData.AppendElements(aBufs);
|
||||
}
|
||||
/*
|
||||
* Generate the whole WebM header and output to mBuff.
|
||||
*/
|
||||
void GenerateHeader();
|
||||
/*
|
||||
* Insert media encoded buffer into muxer and it would be package
|
||||
* into SimpleBlock. If no cluster is opened, new cluster will start for writing.
|
||||
*/
|
||||
void WriteSimpleBlock(EncodedFrame* aFrame);
|
||||
/*
|
||||
* Get valid cluster data.
|
||||
*/
|
||||
void ExtractBuffer(nsTArray<nsTArray<uint8_t> >* aDestBufs,
|
||||
uint32_t aFlag = 0);
|
||||
private:
|
||||
// Close current cluster and move data to mClusterCanFlushBuffs.
|
||||
void FinishCluster();
|
||||
// The temporary storage for cluster data.
|
||||
nsTArray<nsTArray<uint8_t> > mClusterBuffs;
|
||||
// The storage which contain valid cluster data.
|
||||
nsTArray<nsTArray<uint8_t> > mClusterCanFlushBuffs;
|
||||
// Indicate the header index in mClusterBuffs.
|
||||
uint32_t mClusterHeaderIndex;
|
||||
// The cluster length position.
|
||||
uint64_t mClusterLengthLoc;
|
||||
// Audio codec specific header data.
|
||||
nsTArray<uint8_t> mCodecPrivateData;
|
||||
|
||||
// The timecode of the cluster.
|
||||
uint64_t mClusterTimecode;
|
||||
|
||||
// Video configuration
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
float mFrameRate;
|
||||
// Audio configuration
|
||||
float mSampleFreq;
|
||||
int mBitDepth;
|
||||
int mChannels;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,64 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* 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 "WebMWriter.h"
|
||||
#include "EbmlComposer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
WebMWriter::WebMWriter(uint32_t aTrackTypes) : ContainerWriter()
|
||||
{
|
||||
mMetadataRequiredFlag = aTrackTypes;
|
||||
mEbmlComposer = new EbmlComposer();
|
||||
}
|
||||
|
||||
nsresult
|
||||
WebMWriter::WriteEncodedTrack(const EncodedFrameContainer& aData,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
for (uint32_t i = 0 ; i < aData.GetEncodedFrames().Length(); i++) {
|
||||
mEbmlComposer->WriteSimpleBlock(aData.GetEncodedFrames().ElementAt(i).get());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WebMWriter::GetContainerData(nsTArray<nsTArray<uint8_t> >* aOutputBufs,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
mEbmlComposer->ExtractBuffer(aOutputBufs, aFlags);
|
||||
if (aFlags & ContainerWriter::FLUSH_NEEDED) {
|
||||
mIsWritingComplete = true;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WebMWriter::SetMetadata(TrackMetadataBase* aMetadata)
|
||||
{
|
||||
MOZ_ASSERT(aMetadata);
|
||||
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VP8) {
|
||||
VP8Metadata* meta = static_cast<VP8Metadata*>(aMetadata);
|
||||
MOZ_ASSERT(meta, "Cannot find vp8 encoder metadata");
|
||||
mEbmlComposer->SetVideoConfig(meta->mWidth, meta->mHeight,
|
||||
meta->mEncodedFrameRate);
|
||||
mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::HAS_VIDEO;
|
||||
}
|
||||
|
||||
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
|
||||
VorbisMetadata* meta = static_cast<VorbisMetadata*>(aMetadata);
|
||||
MOZ_ASSERT(meta, "Cannot find vorbis encoder metadata");
|
||||
mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels, meta->mBitDepth);
|
||||
mEbmlComposer->SetAudioCodecPrivateData(meta->mData);
|
||||
mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::HAS_AUDIO;
|
||||
}
|
||||
|
||||
if (!mMetadataRequiredFlag) {
|
||||
mEbmlComposer->GenerateHeader();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // mozilla namespace
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* 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/. */
|
||||
|
||||
#ifndef WebMWriter_h_
|
||||
#define WebMWriter_h_
|
||||
|
||||
#include "ContainerWriter.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EbmlComposer;
|
||||
|
||||
// Vorbis meta data structure
|
||||
class VorbisMetadata : public TrackMetadataBase
|
||||
{
|
||||
public:
|
||||
nsTArray<uint8_t> mData;
|
||||
int32_t mChannels;
|
||||
int32_t mBitDepth;
|
||||
float mSamplingFrequency;
|
||||
MetadataKind GetKind() const MOZ_OVERRIDE { return METADATA_VORBIS; }
|
||||
};
|
||||
|
||||
// VP8 meta data structure
|
||||
class VP8Metadata : public TrackMetadataBase
|
||||
{
|
||||
public:
|
||||
int32_t mWidth;
|
||||
int32_t mHeight;
|
||||
int32_t mEncodedFrameRate;
|
||||
MetadataKind GetKind() const MOZ_OVERRIDE { return METADATA_VP8; }
|
||||
};
|
||||
|
||||
/**
|
||||
* WebM writer helper
|
||||
* This class accepts encoder to set audio or video meta data or
|
||||
* encoded data to ebml Composer, and get muxing data through GetContainerData.
|
||||
* The ctor/dtor run in the MediaRecorder thread, others run in MediaEncoder thread.
|
||||
*/
|
||||
class WebMWriter : public ContainerWriter
|
||||
{
|
||||
public:
|
||||
// aTrackTypes indicate this muxer should multiplex into Video only or A/V foramt.
|
||||
// Run in MediaRecorder thread
|
||||
WebMWriter(uint32_t aTrackTypes);
|
||||
// WriteEncodedTrack inserts raw packets into WebM stream.
|
||||
nsresult WriteEncodedTrack(const EncodedFrameContainer &aData,
|
||||
uint32_t aFlags = 0) MOZ_OVERRIDE;
|
||||
|
||||
// GetContainerData outputs multiplexing data.
|
||||
// aFlags indicates the muxer should enter into finished stage and flush out
|
||||
// queue data.
|
||||
nsresult GetContainerData(nsTArray<nsTArray<uint8_t> >* aOutputBufs,
|
||||
uint32_t aFlags = 0) MOZ_OVERRIDE;
|
||||
|
||||
// Assign metadata into muxer
|
||||
nsresult SetMetadata(TrackMetadataBase* aMetadata) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsAutoPtr<EbmlComposer> mEbmlComposer;
|
||||
|
||||
// Indicate what kind of meta data needed in the writer.
|
||||
// If this value become 0, it means writer can start to generate header.
|
||||
uint8_t mMetadataRequiredFlag;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
|
@ -15,6 +15,12 @@ UNIFIED_SOURCES += [
|
|||
'WebMReader.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBM_ENCODER']:
|
||||
EXPORTS += ['WebMWriter.h']
|
||||
UNIFIED_SOURCES += ['EbmlComposer.cpp',
|
||||
'WebMWriter.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
FINAL_LIBRARY = 'gklayout'
|
||||
|
|
|
@ -2682,12 +2682,12 @@ nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile,
|
|||
static bool
|
||||
CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredRegion)
|
||||
{
|
||||
gfxMatrix transform;
|
||||
gfx::Matrix transform;
|
||||
if (!aLayer->GetTransform().Is2D(&transform) ||
|
||||
transform.HasNonIntegerTranslation())
|
||||
return false;
|
||||
transform.NudgeToIntegers();
|
||||
nsIntPoint offset = aOffset + nsIntPoint(transform.x0, transform.y0);
|
||||
nsIntPoint offset = aOffset + nsIntPoint(transform._31, transform._32);
|
||||
|
||||
Layer* child = aLayer->GetFirstChild();
|
||||
if (child) {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef B2G_BDROID_BUILDCFG_H
|
||||
#define B2G_BDROID_BUILDCFG_H
|
||||
|
||||
/**
|
||||
* This header defines B2G common bluedroid build configuration.
|
||||
*
|
||||
* This header is included by
|
||||
* $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR)/bdroid_buildcfg.h,
|
||||
* which applies external configuration onto bluedroid.
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
**
|
||||
** HSP, HFP
|
||||
**
|
||||
******************************************************************************/
|
||||
/* AG feature masks */
|
||||
#define BTIF_HF_FEATURES ( BTA_AG_FEAT_3WAY | \
|
||||
BTA_AG_FEAT_REJECT | \
|
||||
BTA_AG_FEAT_ECS | \
|
||||
BTA_AG_FEAT_EXTERR)
|
||||
|
||||
/* CHLD values */
|
||||
#define BTA_AG_CHLD_VAL "(0,1,2)"
|
||||
|
||||
#endif /* B2G_BDROID_BUILDCFG_H */
|
|
@ -3657,8 +3657,8 @@ let RIL = {
|
|||
|
||||
_sendCallError: function(callIndex, errorMsg) {
|
||||
this.sendChromeMessage({rilMessageType: "callError",
|
||||
callIndex: callIndex,
|
||||
errorMsg: errorMsg});
|
||||
callIndex: callIndex,
|
||||
errorMsg: errorMsg});
|
||||
},
|
||||
|
||||
_sendDataCallError: function(message, errorCode) {
|
||||
|
@ -5095,8 +5095,7 @@ RIL[REQUEST_DIAL] = function REQUEST_DIAL(length, options) {
|
|||
if (options.rilRequestError) {
|
||||
// The connection is not established yet.
|
||||
options.callIndex = -1;
|
||||
this._sendCallError(options.callIndex,
|
||||
RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]);
|
||||
this.getFailCauseCode(options);
|
||||
}
|
||||
};
|
||||
RIL[REQUEST_GET_IMSI] = function REQUEST_GET_IMSI(length, options) {
|
||||
|
@ -9666,6 +9665,13 @@ let ICCPDUHelper = {
|
|||
writeNumberWithLength: function(number) {
|
||||
if (number) {
|
||||
let numStart = number[0] == "+" ? 1 : 0;
|
||||
number = number.substring(0, numStart) +
|
||||
number.substring(numStart)
|
||||
.replace(/[^0-9*#,]/g, "")
|
||||
.replace(/\*/g, "a")
|
||||
.replace(/\#/g, "b")
|
||||
.replace(/\,/g, "c");
|
||||
|
||||
let numDigits = number.length - numStart;
|
||||
if (numDigits > ADN_MAX_NUMBER_DIGITS) {
|
||||
number = number.substring(0, ADN_MAX_NUMBER_DIGITS + numStart);
|
||||
|
|
|
@ -496,27 +496,35 @@ add_test(function test_write_number_with_length() {
|
|||
let helper = worker.GsmPDUHelper;
|
||||
let iccHelper = worker.ICCPDUHelper;
|
||||
|
||||
// without +
|
||||
let number_1 = "123456789";
|
||||
iccHelper.writeNumberWithLength(number_1);
|
||||
let numLen = helper.readHexOctet();
|
||||
do_check_eq(number_1, iccHelper.readDiallingNumber(numLen));
|
||||
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
|
||||
do_check_eq(0xff, helper.readHexOctet());
|
||||
function test(number, expectedNumber) {
|
||||
expectedNumber = expectedNumber || number;
|
||||
iccHelper.writeNumberWithLength(number);
|
||||
let numLen = helper.readHexOctet();
|
||||
do_check_eq(expectedNumber, iccHelper.readDiallingNumber(numLen));
|
||||
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
|
||||
do_check_eq(0xff, helper.readHexOctet());
|
||||
}
|
||||
}
|
||||
|
||||
// without +
|
||||
test("123456789");
|
||||
|
||||
// with +
|
||||
let number_2 = "+987654321";
|
||||
iccHelper.writeNumberWithLength(number_2);
|
||||
numLen = helper.readHexOctet();
|
||||
do_check_eq(number_2, iccHelper.readDiallingNumber(numLen));
|
||||
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
|
||||
do_check_eq(0xff, helper.readHexOctet());
|
||||
}
|
||||
test("+987654321");
|
||||
|
||||
// extended BCD coding
|
||||
test("1*2#3,4*5#6,");
|
||||
|
||||
// with + and extended BCD coding
|
||||
test("+1*2#3,4*5#6,");
|
||||
|
||||
// non-supported characters should not be written.
|
||||
test("(1)23-456+789", "123456789");
|
||||
|
||||
test("++(01)2*3-4#5,6+7(8)9*0#1,", "+012*34#5,6789*0#1,");
|
||||
|
||||
// null
|
||||
let number_3;
|
||||
iccHelper.writeNumberWithLength(number_3);
|
||||
iccHelper.writeNumberWithLength(null);
|
||||
for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES + 1); i++) {
|
||||
do_check_eq(0xff, helper.readHexOctet());
|
||||
}
|
||||
|
|
|
@ -67,7 +67,6 @@ html|input.num {
|
|||
}
|
||||
|
||||
html|div.plainfield {
|
||||
-moz-margin-start: 1px;
|
||||
color: -moz-fieldtext;
|
||||
white-space: pre;
|
||||
}
|
||||
|
|
|
@ -206,6 +206,10 @@ public:
|
|||
FuzzyEqual(_32, floorf(_32 + 0.5f));
|
||||
}
|
||||
|
||||
Point GetTranslation() const {
|
||||
return Point(_31, _32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if matrix is multiple of 90 degrees rotation with flipping,
|
||||
* scaling and translation.
|
||||
|
@ -259,6 +263,21 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Is2D(Matrix* aMatrix) const {
|
||||
if (!Is2D()) {
|
||||
return false;
|
||||
}
|
||||
if (aMatrix) {
|
||||
aMatrix->_11 = _11;
|
||||
aMatrix->_12 = _12;
|
||||
aMatrix->_21 = _21;
|
||||
aMatrix->_22 = _22;
|
||||
aMatrix->_31 = _41;
|
||||
aMatrix->_32 = _42;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Matrix As2D() const
|
||||
{
|
||||
MOZ_ASSERT(Is2D(), "Matrix is not a 2D affine transform");
|
||||
|
@ -266,6 +285,45 @@ public:
|
|||
return Matrix(_11, _12, _21, _22, _41, _42);
|
||||
}
|
||||
|
||||
bool CanDraw2D(Matrix* aMatrix = nullptr) const {
|
||||
if (_14 != 0.0f ||
|
||||
_24 != 0.0f ||
|
||||
_44 != 1.0f) {
|
||||
return false;
|
||||
}
|
||||
if (aMatrix) {
|
||||
aMatrix->_11 = _11;
|
||||
aMatrix->_12 = _12;
|
||||
aMatrix->_21 = _21;
|
||||
aMatrix->_22 = _22;
|
||||
aMatrix->_31 = _41;
|
||||
aMatrix->_32 = _42;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Matrix4x4& ProjectTo2D() {
|
||||
_31 = 0.0f;
|
||||
_32 = 0.0f;
|
||||
_13 = 0.0f;
|
||||
_23 = 0.0f;
|
||||
_33 = 1.0f;
|
||||
_43 = 0.0f;
|
||||
_34 = 0.0f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
static Matrix4x4 From2D(const Matrix &aMatrix) {
|
||||
Matrix4x4 matrix;
|
||||
matrix._11 = aMatrix._11;
|
||||
matrix._12 = aMatrix._12;
|
||||
matrix._21 = aMatrix._21;
|
||||
matrix._22 = aMatrix._22;
|
||||
matrix._41 = aMatrix._31;
|
||||
matrix._42 = aMatrix._32;
|
||||
return matrix;
|
||||
}
|
||||
|
||||
bool Is2DIntegerTranslation() const
|
||||
{
|
||||
return Is2D() && As2D().IsIntegerTranslation();
|
||||
|
@ -288,6 +346,16 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
Matrix4x4 &Translate(Float aX, Float aY, Float aZ)
|
||||
{
|
||||
_41 += aX * _11 + aY * _21 + aZ * _31;
|
||||
_42 += aX * _12 + aY * _22 + aZ * _32;
|
||||
_43 += aX * _13 + aY * _23 + aZ * _33;
|
||||
_44 += aX * _14 + aY * _24 + aZ * _34;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Matrix4x4& o) const
|
||||
{
|
||||
// XXX would be nice to memcmp here, but that breaks IEEE 754 semantics
|
||||
|
|
|
@ -80,6 +80,32 @@ struct ParamTraits<mozilla::gfx::Matrix>
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<mozilla::gfx::Matrix4x4>
|
||||
{
|
||||
typedef mozilla::gfx::Matrix4x4 paramType;
|
||||
|
||||
static void Write(Message* msg, const paramType& param)
|
||||
{
|
||||
#define Wr(_f) WriteParam(msg, param. _f)
|
||||
Wr(_11); Wr(_12); Wr(_13); Wr(_14);
|
||||
Wr(_21); Wr(_22); Wr(_23); Wr(_24);
|
||||
Wr(_31); Wr(_32); Wr(_33); Wr(_34);
|
||||
Wr(_41); Wr(_42); Wr(_43); Wr(_44);
|
||||
#undef Wr
|
||||
}
|
||||
|
||||
static bool Read(const Message* msg, void** iter, paramType* result)
|
||||
{
|
||||
#define Rd(_f) ReadParam(msg, iter, &result-> _f)
|
||||
return (Rd(_11) && Rd(_12) && Rd(_13) && Rd(_14) &&
|
||||
Rd(_21) && Rd(_22) && Rd(_23) && Rd(_24) &&
|
||||
Rd(_31) && Rd(_32) && Rd(_33) && Rd(_34) &&
|
||||
Rd(_41) && Rd(_42) && Rd(_43) && Rd(_44));
|
||||
#undef Rd
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<gfxPoint>
|
||||
{
|
||||
|
|
|
@ -27,9 +27,9 @@ void ImageLayer::SetContainer(ImageContainer* aContainer)
|
|||
mContainer = aContainer;
|
||||
}
|
||||
|
||||
void ImageLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
void ImageLayer::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
gfx3DMatrix local = GetLocalTransform();
|
||||
gfx::Matrix4x4 local = GetLocalTransform();
|
||||
|
||||
// Snap image edges to pixel boundaries
|
||||
gfxRect sourceRect(0, 0, 0, 0);
|
||||
|
@ -47,10 +47,9 @@ void ImageLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurfa
|
|||
// This makes our snapping equivalent to what would happen if our content
|
||||
// was drawn into a ThebesLayer (gfxContext would snap using the local
|
||||
// transform, then we'd snap again when compositing the ThebesLayer).
|
||||
gfx3DMatrix snappedTransform =
|
||||
mEffectiveTransform =
|
||||
SnapTransform(local, sourceRect, nullptr) *
|
||||
SnapTransformTranslation(aTransformToSurface, nullptr);
|
||||
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
|
||||
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nscore.h" // for nsACString
|
||||
|
||||
class gfx3DMatrix;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
|
@ -67,7 +65,7 @@ public:
|
|||
|
||||
MOZ_LAYER_DECL_NAME("ImageLayer", TYPE_IMAGE)
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface);
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface);
|
||||
|
||||
/**
|
||||
* if true, the image will only be backed by a single tile texture
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "limits.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
|
@ -78,8 +80,10 @@ static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) {
|
|||
gfxRect ourRect = aOne->GetEffectiveVisibleRegion().GetBounds();
|
||||
gfxRect otherRect = aTwo->GetEffectiveVisibleRegion().GetBounds();
|
||||
|
||||
gfx3DMatrix ourTransform = aOne->GetTransform();
|
||||
gfx3DMatrix otherTransform = aTwo->GetTransform();
|
||||
gfx3DMatrix ourTransform;
|
||||
To3DMatrix(aOne->GetTransform(), ourTransform);
|
||||
gfx3DMatrix otherTransform;
|
||||
To3DMatrix(aTwo->GetTransform(), otherTransform);
|
||||
|
||||
// Transform both rectangles and project into 2d space.
|
||||
gfxQuad ourTransformedRect = ourTransform.TransformRect(ourRect);
|
||||
|
|
|
@ -111,7 +111,6 @@ struct LayerPropertiesBase : public LayerProperties
|
|||
, mMaskLayer(nullptr)
|
||||
, mVisibleRegion(aLayer->GetVisibleRegion())
|
||||
, mInvalidRegion(aLayer->GetInvalidRegion())
|
||||
, mTransform(aLayer->GetTransform())
|
||||
, mOpacity(aLayer->GetOpacity())
|
||||
, mUseClipRect(!!aLayer->GetClipRect())
|
||||
{
|
||||
|
@ -122,6 +121,7 @@ struct LayerPropertiesBase : public LayerProperties
|
|||
if (mUseClipRect) {
|
||||
mClipRect = *aLayer->GetClipRect();
|
||||
}
|
||||
gfx::To3DMatrix(aLayer->GetTransform(), mTransform);
|
||||
}
|
||||
LayerPropertiesBase()
|
||||
: mLayer(nullptr)
|
||||
|
@ -141,7 +141,9 @@ struct LayerPropertiesBase : public LayerProperties
|
|||
|
||||
nsIntRegion ComputeChange(NotifySubDocInvalidationFunc aCallback)
|
||||
{
|
||||
bool transformChanged = !mTransform.FuzzyEqual(mLayer->GetTransform());
|
||||
gfx3DMatrix transform;
|
||||
gfx::To3DMatrix(mLayer->GetTransform(), transform);
|
||||
bool transformChanged = !mTransform.FuzzyEqual(transform);
|
||||
Layer* otherMask = mLayer->GetMaskLayer();
|
||||
const nsIntRect* otherClip = mLayer->GetClipRect();
|
||||
nsIntRegion result;
|
||||
|
@ -189,7 +191,9 @@ struct LayerPropertiesBase : public LayerProperties
|
|||
|
||||
nsIntRect NewTransformedBounds()
|
||||
{
|
||||
return TransformRect(mLayer->GetVisibleRegion().GetBounds(), mLayer->GetTransform());
|
||||
gfx3DMatrix transform;
|
||||
gfx::To3DMatrix(mLayer->GetTransform(), transform);
|
||||
return TransformRect(mLayer->GetVisibleRegion().GetBounds(), transform);
|
||||
}
|
||||
|
||||
nsIntRect OldTransformedBounds()
|
||||
|
@ -271,7 +275,9 @@ struct ContainerLayerProperties : public LayerPropertiesBase
|
|||
invalidateChildsCurrentArea = true;
|
||||
}
|
||||
if (invalidateChildsCurrentArea) {
|
||||
AddTransformedRegion(result, child->GetVisibleRegion(), child->GetTransform());
|
||||
gfx3DMatrix transform;
|
||||
gfx::To3DMatrix(child->GetTransform(), transform);
|
||||
AddTransformedRegion(result, child->GetVisibleRegion(), transform);
|
||||
if (aCallback) {
|
||||
NotifySubdocumentInvalidationRecursive(child, aCallback);
|
||||
} else {
|
||||
|
@ -290,7 +296,9 @@ struct ContainerLayerProperties : public LayerPropertiesBase
|
|||
aCallback(container, result);
|
||||
}
|
||||
|
||||
return TransformRegion(result, mLayer->GetTransform());
|
||||
gfx3DMatrix transform;
|
||||
gfx::To3DMatrix(mLayer->GetTransform(), transform);
|
||||
return TransformRegion(result, transform);
|
||||
}
|
||||
|
||||
// The old list of children:
|
||||
|
@ -406,7 +414,9 @@ LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFu
|
|||
} else {
|
||||
ClearInvalidations(aRoot);
|
||||
}
|
||||
nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(), aRoot->GetTransform());
|
||||
gfx3DMatrix transform;
|
||||
gfx::To3DMatrix(aRoot->GetTransform(), transform);
|
||||
nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(), transform);
|
||||
result = result.Union(OldTransformedBounds());
|
||||
return result;
|
||||
} else {
|
||||
|
|
|
@ -306,7 +306,7 @@ CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
|
|||
case TransformFunction::TTransformMatrix:
|
||||
{
|
||||
arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_matrix3d, resultTail);
|
||||
const gfx3DMatrix& matrix = aFunctions[i].get_TransformMatrix().value();
|
||||
const gfx::Matrix4x4& matrix = aFunctions[i].get_TransformMatrix().value();
|
||||
arr->Item(1).SetFloatValue(matrix._11, eCSSUnit_Number);
|
||||
arr->Item(2).SetFloatValue(matrix._12, eCSSUnit_Number);
|
||||
arr->Item(3).SetFloatValue(matrix._13, eCSSUnit_Number);
|
||||
|
@ -467,30 +467,31 @@ Layer::GetEffectiveVisibleRegion()
|
|||
return GetVisibleRegion();
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
Layer::SnapTransformTranslation(const gfx3DMatrix& aTransform,
|
||||
gfxMatrix* aResidualTransform)
|
||||
Matrix4x4
|
||||
Layer::SnapTransformTranslation(const Matrix4x4& aTransform,
|
||||
Matrix* aResidualTransform)
|
||||
{
|
||||
if (aResidualTransform) {
|
||||
*aResidualTransform = gfxMatrix();
|
||||
*aResidualTransform = Matrix();
|
||||
}
|
||||
|
||||
gfxMatrix matrix2D;
|
||||
gfx3DMatrix result;
|
||||
Matrix matrix2D;
|
||||
Matrix4x4 result;
|
||||
if (mManager->IsSnappingEffectiveTransforms() &&
|
||||
aTransform.Is2D(&matrix2D) &&
|
||||
!matrix2D.HasNonTranslation() &&
|
||||
matrix2D.HasNonIntegerTranslation()) {
|
||||
gfxPoint snappedTranslation(matrix2D.GetTranslation());
|
||||
snappedTranslation.Round();
|
||||
gfxMatrix snappedMatrix = gfxMatrix().Translate(snappedTranslation);
|
||||
result = gfx3DMatrix::From2D(snappedMatrix);
|
||||
IntPoint snappedTranslation = RoundedToInt(matrix2D.GetTranslation());
|
||||
Matrix snappedMatrix = Matrix().Translate(snappedTranslation.x,
|
||||
snappedTranslation.y);
|
||||
result = Matrix4x4::From2D(snappedMatrix);
|
||||
if (aResidualTransform) {
|
||||
// set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
|
||||
// (I.e., appying snappedMatrix after aResidualTransform gives the
|
||||
// ideal transform.)
|
||||
*aResidualTransform =
|
||||
gfxMatrix().Translate(matrix2D.GetTranslation() - snappedTranslation);
|
||||
Matrix().Translate(matrix2D._31 - snappedTranslation.x,
|
||||
matrix2D._32 - snappedTranslation.y);
|
||||
}
|
||||
} else {
|
||||
result = aTransform;
|
||||
|
@ -498,37 +499,34 @@ Layer::SnapTransformTranslation(const gfx3DMatrix& aTransform,
|
|||
return result;
|
||||
}
|
||||
|
||||
gfx3DMatrix
|
||||
Layer::SnapTransform(const gfx3DMatrix& aTransform,
|
||||
Matrix4x4
|
||||
Layer::SnapTransform(const Matrix4x4& aTransform,
|
||||
const gfxRect& aSnapRect,
|
||||
gfxMatrix* aResidualTransform)
|
||||
Matrix* aResidualTransform)
|
||||
{
|
||||
if (aResidualTransform) {
|
||||
*aResidualTransform = gfxMatrix();
|
||||
*aResidualTransform = Matrix();
|
||||
}
|
||||
|
||||
gfxMatrix matrix2D;
|
||||
gfx3DMatrix result;
|
||||
Matrix matrix2D;
|
||||
Matrix4x4 result;
|
||||
if (mManager->IsSnappingEffectiveTransforms() &&
|
||||
aTransform.Is2D(&matrix2D) &&
|
||||
gfx::Size(1.0, 1.0) <= ToSize(aSnapRect.Size()) &&
|
||||
matrix2D.PreservesAxisAlignedRectangles()) {
|
||||
gfxPoint transformedTopLeft = matrix2D.Transform(aSnapRect.TopLeft());
|
||||
transformedTopLeft.Round();
|
||||
gfxPoint transformedTopRight = matrix2D.Transform(aSnapRect.TopRight());
|
||||
transformedTopRight.Round();
|
||||
gfxPoint transformedBottomRight = matrix2D.Transform(aSnapRect.BottomRight());
|
||||
transformedBottomRight.Round();
|
||||
IntPoint transformedTopLeft = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopLeft()));
|
||||
IntPoint transformedTopRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.TopRight()));
|
||||
IntPoint transformedBottomRight = RoundedToInt(matrix2D * ToPoint(aSnapRect.BottomRight()));
|
||||
|
||||
gfxMatrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect,
|
||||
Matrix snappedMatrix = gfxUtils::TransformRectToRect(aSnapRect,
|
||||
transformedTopLeft, transformedTopRight, transformedBottomRight);
|
||||
|
||||
result = gfx3DMatrix::From2D(snappedMatrix);
|
||||
result = Matrix4x4::From2D(snappedMatrix);
|
||||
if (aResidualTransform && !snappedMatrix.IsSingular()) {
|
||||
// set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
|
||||
// (i.e., appying snappedMatrix after aResidualTransform gives the
|
||||
// ideal transform.
|
||||
gfxMatrix snappedMatrixInverse = snappedMatrix;
|
||||
Matrix snappedMatrixInverse = snappedMatrix;
|
||||
snappedMatrixInverse.Invert();
|
||||
*aResidualTransform = matrix2D * snappedMatrixInverse;
|
||||
}
|
||||
|
@ -552,11 +550,9 @@ AncestorLayerMayChangeTransform(Layer* aLayer)
|
|||
bool
|
||||
Layer::MayResample()
|
||||
{
|
||||
gfxMatrix transform2d;
|
||||
gfx3DMatrix effectiveTransform;
|
||||
To3DMatrix(GetEffectiveTransform(), effectiveTransform);
|
||||
return !effectiveTransform.Is2D(&transform2d) ||
|
||||
transform2d.HasNonIntegerTranslation() ||
|
||||
Matrix transform2d;
|
||||
return !GetEffectiveTransform().Is2D(&transform2d) ||
|
||||
ThebesMatrix(transform2d).HasNonIntegerTranslation() ||
|
||||
AncestorLayerMayChangeTransform(this);
|
||||
}
|
||||
|
||||
|
@ -619,21 +615,21 @@ Layer::CalculateScissorRect(const nsIntRect& aCurrentScissorRect,
|
|||
return currentClip.Intersect(scissor);
|
||||
}
|
||||
|
||||
const gfx3DMatrix
|
||||
const Matrix4x4
|
||||
Layer::GetTransform() const
|
||||
{
|
||||
gfx3DMatrix transform = mTransform;
|
||||
Matrix4x4 transform = mTransform;
|
||||
if (const ContainerLayer* c = AsContainerLayer()) {
|
||||
transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
|
||||
}
|
||||
transform.ScalePost(mPostXScale, mPostYScale, 1.0f);
|
||||
transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
|
||||
return transform;
|
||||
}
|
||||
|
||||
const gfx3DMatrix
|
||||
const Matrix4x4
|
||||
Layer::GetLocalTransform()
|
||||
{
|
||||
gfx3DMatrix transform;
|
||||
Matrix4x4 transform;
|
||||
if (LayerComposite* shadow = AsLayerComposite())
|
||||
transform = shadow->GetShadowTransform();
|
||||
else
|
||||
|
@ -641,7 +637,8 @@ Layer::GetLocalTransform()
|
|||
if (ContainerLayer* c = AsContainerLayer()) {
|
||||
transform.Scale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
|
||||
}
|
||||
transform.ScalePost(mPostXScale, mPostYScale, 1.0f);
|
||||
transform = transform * Matrix4x4().Scale(mPostXScale, mPostYScale, 1.0f);
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
|
@ -690,19 +687,16 @@ Layer::GetEffectiveMixBlendMode()
|
|||
}
|
||||
|
||||
void
|
||||
Layer::ComputeEffectiveTransformForMaskLayer(const gfx3DMatrix& aTransformToSurface)
|
||||
Layer::ComputeEffectiveTransformForMaskLayer(const Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
if (mMaskLayer) {
|
||||
ToMatrix4x4(aTransformToSurface, mMaskLayer->mEffectiveTransform);
|
||||
mMaskLayer->mEffectiveTransform = aTransformToSurface;
|
||||
|
||||
#ifdef DEBUG
|
||||
gfxMatrix maskTranslation;
|
||||
bool maskIs2D = mMaskLayer->GetTransform().CanDraw2D(&maskTranslation);
|
||||
bool maskIs2D = mMaskLayer->GetTransform().CanDraw2D();
|
||||
NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
|
||||
#endif
|
||||
Matrix4x4 maskTransform;
|
||||
ToMatrix4x4(mMaskLayer->GetTransform(), maskTransform);
|
||||
mMaskLayer->mEffectiveTransform = maskTransform * mMaskLayer->mEffectiveTransform;
|
||||
mMaskLayer->mEffectiveTransform = mMaskLayer->GetTransform() * mMaskLayer->mEffectiveTransform;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -887,13 +881,12 @@ ContainerLayer::SortChildrenBy3DZOrder(nsTArray<Layer*>& aArray)
|
|||
}
|
||||
|
||||
void
|
||||
ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
ContainerLayer::DefaultComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
gfxMatrix residual;
|
||||
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
|
||||
Matrix residual;
|
||||
Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
|
||||
idealTransform.ProjectTo2D();
|
||||
gfx3DMatrix snappedTransform = SnapTransformTranslation(idealTransform, &residual);
|
||||
ToMatrix4x4(snappedTransform, mEffectiveTransform);
|
||||
mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual);
|
||||
|
||||
bool useIntermediateSurface;
|
||||
if (GetMaskLayer()) {
|
||||
|
@ -936,7 +929,7 @@ ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformT
|
|||
|
||||
mUseIntermediateSurface = useIntermediateSurface;
|
||||
if (useIntermediateSurface) {
|
||||
ComputeEffectiveTransformsForChildren(gfx3DMatrix::From2D(residual));
|
||||
ComputeEffectiveTransformsForChildren(Matrix4x4::From2D(residual));
|
||||
} else {
|
||||
ComputeEffectiveTransformsForChildren(idealTransform);
|
||||
}
|
||||
|
@ -944,12 +937,12 @@ ContainerLayer::DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformT
|
|||
if (idealTransform.CanDraw2D()) {
|
||||
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
|
||||
} else {
|
||||
ComputeEffectiveTransformForMaskLayer(gfx3DMatrix());
|
||||
ComputeEffectiveTransformForMaskLayer(Matrix4x4());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContainerLayer::ComputeEffectiveTransformsForChildren(const gfx3DMatrix& aTransformToSurface)
|
||||
ContainerLayer::ComputeEffectiveTransformsForChildren(const Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
|
||||
l->ComputeEffectiveTransforms(aTransformToSurface);
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <sys/types.h> // for int32_t, int64_t
|
||||
#include "FrameMetrics.h" // for FrameMetrics
|
||||
#include "Units.h" // for LayerMargin, LayerPoint
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "gfxContext.h" // for GraphicsOperator
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxColor.h" // for gfxRGBA
|
||||
|
@ -867,8 +866,7 @@ public:
|
|||
{
|
||||
#ifdef DEBUG
|
||||
if (aMaskLayer) {
|
||||
gfxMatrix maskTransform;
|
||||
bool maskIs2D = aMaskLayer->GetTransform().CanDraw2D(&maskTransform);
|
||||
bool maskIs2D = aMaskLayer->GetTransform().CanDraw2D();
|
||||
NS_ASSERTION(maskIs2D, "Mask layer has invalid transform.");
|
||||
}
|
||||
#endif
|
||||
|
@ -885,7 +883,7 @@ public:
|
|||
* Tell this layer what its transform should be. The transformation
|
||||
* is applied when compositing the layer into its parent container.
|
||||
*/
|
||||
void SetBaseTransform(const gfx3DMatrix& aMatrix)
|
||||
void SetBaseTransform(const gfx::Matrix4x4& aMatrix)
|
||||
{
|
||||
NS_ASSERTION(!aMatrix.IsSingular(),
|
||||
"Shouldn't be trying to draw with a singular matrix!");
|
||||
|
@ -906,9 +904,9 @@ public:
|
|||
* method enqueues a new transform value to be set immediately after
|
||||
* the next transaction is opened.
|
||||
*/
|
||||
void SetBaseTransformForNextTransaction(const gfx3DMatrix& aMatrix)
|
||||
void SetBaseTransformForNextTransaction(const gfx::Matrix4x4& aMatrix)
|
||||
{
|
||||
mPendingTransform = new gfx3DMatrix(aMatrix);
|
||||
mPendingTransform = new gfx::Matrix4x4(aMatrix);
|
||||
}
|
||||
|
||||
void SetPostScale(float aXScale, float aYScale)
|
||||
|
@ -1047,8 +1045,8 @@ public:
|
|||
const Layer* GetPrevSibling() const { return mPrevSibling; }
|
||||
virtual Layer* GetFirstChild() const { return nullptr; }
|
||||
virtual Layer* GetLastChild() const { return nullptr; }
|
||||
const gfx3DMatrix GetTransform() const;
|
||||
const gfx3DMatrix& GetBaseTransform() const { return mTransform; }
|
||||
const gfx::Matrix4x4 GetTransform() const;
|
||||
const gfx::Matrix4x4& GetBaseTransform() const { return mTransform; }
|
||||
float GetPostXScale() const { return mPostXScale; }
|
||||
float GetPostYScale() const { return mPostYScale; }
|
||||
bool GetIsFixedPosition() { return mIsFixedPosition; }
|
||||
|
@ -1074,7 +1072,7 @@ public:
|
|||
* Returns the local transform for this layer: either mTransform or,
|
||||
* for shadow layers, GetShadowTransform()
|
||||
*/
|
||||
const gfx3DMatrix GetLocalTransform();
|
||||
const gfx::Matrix4x4 GetLocalTransform();
|
||||
|
||||
/**
|
||||
* Returns the local opacity for this layer: either mOpacity or,
|
||||
|
@ -1232,12 +1230,12 @@ public:
|
|||
* We promise that when this is called on a layer, all ancestor layers
|
||||
* have already had ComputeEffectiveTransforms called.
|
||||
*/
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) = 0;
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) = 0;
|
||||
|
||||
/**
|
||||
* computes the effective transform for a mask layer, if this layer has one
|
||||
*/
|
||||
void ComputeEffectiveTransformForMaskLayer(const gfx3DMatrix& aTransformToSurface);
|
||||
void ComputeEffectiveTransformForMaskLayer(const gfx::Matrix4x4& aTransformToSurface);
|
||||
|
||||
/**
|
||||
* Calculate the scissor rect required when rendering this layer.
|
||||
|
@ -1365,8 +1363,8 @@ protected:
|
|||
* @param aResidualTransform a transform to apply before the result transform
|
||||
* in order to get the results to completely match aTransform.
|
||||
*/
|
||||
gfx3DMatrix SnapTransformTranslation(const gfx3DMatrix& aTransform,
|
||||
gfxMatrix* aResidualTransform);
|
||||
gfx::Matrix4x4 SnapTransformTranslation(const gfx::Matrix4x4& aTransform,
|
||||
gfx::Matrix* aResidualTransform);
|
||||
/**
|
||||
* See comment for SnapTransformTranslation.
|
||||
* This function implements type 2 snapping. If aTransform is a translation
|
||||
|
@ -1378,9 +1376,9 @@ protected:
|
|||
* @param aResidualTransform a transform to apply before the result transform
|
||||
* in order to get the results to completely match aTransform.
|
||||
*/
|
||||
gfx3DMatrix SnapTransform(const gfx3DMatrix& aTransform,
|
||||
const gfxRect& aSnapRect,
|
||||
gfxMatrix* aResidualTransform);
|
||||
gfx::Matrix4x4 SnapTransform(const gfx::Matrix4x4& aTransform,
|
||||
const gfxRect& aSnapRect,
|
||||
gfx::Matrix* aResidualTransform);
|
||||
|
||||
/**
|
||||
* Returns true if this layer's effective transform is not just
|
||||
|
@ -1399,11 +1397,11 @@ protected:
|
|||
gfx::UserData mUserData;
|
||||
nsIntRegion mVisibleRegion;
|
||||
EventRegions mEventRegions;
|
||||
gfx3DMatrix mTransform;
|
||||
gfx::Matrix4x4 mTransform;
|
||||
// A mutation of |mTransform| that we've queued to be applied at the
|
||||
// end of the next transaction (if nothing else overrides it in the
|
||||
// meantime).
|
||||
nsAutoPtr<gfx3DMatrix> mPendingTransform;
|
||||
nsAutoPtr<gfx::Matrix4x4> mPendingTransform;
|
||||
float mPostXScale;
|
||||
float mPostYScale;
|
||||
gfx::Matrix4x4 mEffectiveTransform;
|
||||
|
@ -1478,19 +1476,18 @@ public:
|
|||
|
||||
MOZ_LAYER_DECL_NAME("ThebesLayer", TYPE_THEBES)
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
|
||||
gfxMatrix residual;
|
||||
gfx3DMatrix snappedTransform = SnapTransformTranslation(idealTransform,
|
||||
gfx::Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
|
||||
gfx::Matrix residual;
|
||||
mEffectiveTransform = SnapTransformTranslation(idealTransform,
|
||||
mAllowResidualTranslation ? &residual : nullptr);
|
||||
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
|
||||
// The residual can only be a translation because SnapTransformTranslation
|
||||
// only changes the transform if it's a translation
|
||||
NS_ASSERTION(!residual.HasNonTranslation(),
|
||||
NS_ASSERTION(residual.IsTranslation(),
|
||||
"Residual transform can only be a translation");
|
||||
if (!residual.GetTranslation().WithinEpsilonOf(mResidualTranslation, 1e-3f)) {
|
||||
mResidualTranslation = residual.GetTranslation();
|
||||
if (!gfx::ThebesPoint(residual.GetTranslation()).WithinEpsilonOf(mResidualTranslation, 1e-3f)) {
|
||||
mResidualTranslation = gfx::ThebesPoint(residual.GetTranslation());
|
||||
NS_ASSERTION(-0.5 <= mResidualTranslation.x && mResidualTranslation.x < 0.5 &&
|
||||
-0.5 <= mResidualTranslation.y && mResidualTranslation.y < 0.5,
|
||||
"Residual translation out of range");
|
||||
|
@ -1642,7 +1639,7 @@ public:
|
|||
* container is backend-specific. ComputeEffectiveTransforms must also set
|
||||
* mUseIntermediateSurface.
|
||||
*/
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) = 0;
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) = 0;
|
||||
|
||||
/**
|
||||
* Call this only after ComputeEffectiveTransforms has been invoked
|
||||
|
@ -1687,12 +1684,12 @@ protected:
|
|||
* A default implementation of ComputeEffectiveTransforms for use by OpenGL
|
||||
* and D3D.
|
||||
*/
|
||||
void DefaultComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface);
|
||||
void DefaultComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface);
|
||||
|
||||
/**
|
||||
* Loops over the children calling ComputeEffectiveTransforms on them.
|
||||
*/
|
||||
void ComputeEffectiveTransformsForChildren(const gfx3DMatrix& aTransformToSurface);
|
||||
void ComputeEffectiveTransformsForChildren(const gfx::Matrix4x4& aTransformToSurface);
|
||||
|
||||
virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
|
||||
|
||||
|
@ -1751,11 +1748,10 @@ public:
|
|||
|
||||
MOZ_LAYER_DECL_NAME("ColorLayer", TYPE_COLOR)
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
|
||||
gfx3DMatrix snappedTransform = SnapTransformTranslation(idealTransform, nullptr);
|
||||
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
|
||||
gfx::Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
|
||||
mEffectiveTransform = SnapTransformTranslation(idealTransform, nullptr);
|
||||
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
|
||||
}
|
||||
|
||||
|
@ -1892,17 +1888,16 @@ public:
|
|||
|
||||
MOZ_LAYER_DECL_NAME("CanvasLayer", TYPE_CANVAS)
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
// Snap our local transform first, and snap the inherited transform as well.
|
||||
// This makes our snapping equivalent to what would happen if our content
|
||||
// was drawn into a ThebesLayer (gfxContext would snap using the local
|
||||
// transform, then we'd snap again when compositing the ThebesLayer).
|
||||
gfx3DMatrix snappedTransform =
|
||||
mEffectiveTransform =
|
||||
SnapTransform(GetLocalTransform(), gfxRect(0, 0, mBounds.width, mBounds.height),
|
||||
nullptr)*
|
||||
SnapTransformTranslation(aTransformToSurface, nullptr);
|
||||
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
|
||||
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "MacIOSurfaceImage.h"
|
||||
#include "mozilla/layers/MacIOSurfaceTextureClientOGL.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
TextureClient*
|
||||
|
@ -19,3 +20,34 @@ MacIOSurfaceImage::GetTextureClient()
|
|||
}
|
||||
return mTextureClient;
|
||||
}
|
||||
|
||||
TemporaryRef<gfx::SourceSurface>
|
||||
MacIOSurfaceImage::GetAsSourceSurface()
|
||||
{
|
||||
mSurface->Lock();
|
||||
size_t bytesPerRow = mSurface->GetBytesPerRow();
|
||||
size_t ioWidth = mSurface->GetDevicePixelWidth();
|
||||
size_t ioHeight = mSurface->GetDevicePixelHeight();
|
||||
|
||||
unsigned char* ioData = (unsigned char*)mSurface->GetBaseAddress();
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> dataSurface
|
||||
= gfx::Factory::CreateDataSourceSurface(gfx::IntSize(ioWidth, ioHeight), gfx::SurfaceFormat::B8G8R8A8);
|
||||
if (!dataSurface)
|
||||
return nullptr;
|
||||
|
||||
gfx::DataSourceSurface::MappedSurface mappedSurface;
|
||||
if (!dataSurface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface))
|
||||
return nullptr;
|
||||
|
||||
for (size_t i = 0; i < ioHeight; ++i) {
|
||||
memcpy(mappedSurface.mData + i * mappedSurface.mStride,
|
||||
ioData + i * bytesPerRow,
|
||||
ioWidth * 4);
|
||||
}
|
||||
|
||||
dataSurface->Unmap();
|
||||
mSurface->Unlock();
|
||||
|
||||
return dataSurface;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ public:
|
|||
return imgSurface.forget();
|
||||
}
|
||||
|
||||
virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface();
|
||||
|
||||
virtual TextureClient* GetTextureClient() MOZ_OVERRIDE;
|
||||
virtual uint8_t* GetBuffer() MOZ_OVERRIDE { return nullptr; }
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <stdint.h> // for uint64_t
|
||||
#include "Layers.h" // for Layer, etc
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "gfxColor.h" // for gfxRGBA
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
|
@ -84,17 +83,16 @@ class ReadbackLayer : public Layer {
|
|||
public:
|
||||
MOZ_LAYER_DECL_NAME("ReadbackLayer", TYPE_READBACK)
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
// Snap our local transform first, and snap the inherited transform as well.
|
||||
// This makes our snapping equivalent to what would happen if our content
|
||||
// was drawn into a ThebesLayer (gfxContext would snap using the local
|
||||
// transform, then we'd snap again when compositing the ThebesLayer).
|
||||
gfx3DMatrix snappedTransform =
|
||||
mEffectiveTransform =
|
||||
SnapTransform(GetLocalTransform(), gfxRect(0, 0, mSize.width, mSize.height),
|
||||
nullptr)*
|
||||
SnapTransformTranslation(aTransformToSurface, nullptr);
|
||||
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,19 +46,19 @@ ReadbackProcessor::BuildUpdates(ContainerLayer* aContainer)
|
|||
static Layer*
|
||||
FindBackgroundLayer(ReadbackLayer* aLayer, nsIntPoint* aOffset)
|
||||
{
|
||||
gfxMatrix transform;
|
||||
gfx::Matrix transform;
|
||||
if (!aLayer->GetTransform().Is2D(&transform) ||
|
||||
transform.HasNonIntegerTranslation())
|
||||
return nullptr;
|
||||
nsIntPoint transformOffset(int32_t(transform.x0), int32_t(transform.y0));
|
||||
nsIntPoint transformOffset(int32_t(transform._31), int32_t(transform._32));
|
||||
|
||||
for (Layer* l = aLayer->GetPrevSibling(); l; l = l->GetPrevSibling()) {
|
||||
gfxMatrix backgroundTransform;
|
||||
gfx::Matrix backgroundTransform;
|
||||
if (!l->GetTransform().Is2D(&backgroundTransform) ||
|
||||
backgroundTransform.HasNonIntegerTranslation())
|
||||
gfx::ThebesMatrix(backgroundTransform).HasNonIntegerTranslation())
|
||||
return nullptr;
|
||||
|
||||
nsIntPoint backgroundOffset(int32_t(backgroundTransform.x0), int32_t(backgroundTransform.y0));
|
||||
nsIntPoint backgroundOffset(int32_t(backgroundTransform._31), int32_t(backgroundTransform._32));
|
||||
nsIntRect rectInBackground(transformOffset - backgroundOffset, aLayer->GetSize());
|
||||
const nsIntRegion& visibleRegion = l->GetEffectiveVisibleRegion();
|
||||
if (!visibleRegion.Intersects(rectInBackground))
|
||||
|
|
|
@ -34,31 +34,30 @@ BasicContainerLayer::~BasicContainerLayer()
|
|||
}
|
||||
|
||||
void
|
||||
BasicContainerLayer::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
// We push groups for container layers if we need to, which always
|
||||
// are aligned in device space, so it doesn't really matter how we snap
|
||||
// containers.
|
||||
gfxMatrix residual;
|
||||
gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
|
||||
Matrix residual;
|
||||
Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
|
||||
idealTransform.ProjectTo2D();
|
||||
|
||||
if (!idealTransform.CanDraw2D()) {
|
||||
ToMatrix4x4(idealTransform, mEffectiveTransform);
|
||||
ComputeEffectiveTransformsForChildren(gfx3DMatrix());
|
||||
ComputeEffectiveTransformForMaskLayer(gfx3DMatrix());
|
||||
mEffectiveTransform = idealTransform;
|
||||
ComputeEffectiveTransformsForChildren(Matrix4x4());
|
||||
ComputeEffectiveTransformForMaskLayer(Matrix4x4());
|
||||
mUseIntermediateSurface = true;
|
||||
return;
|
||||
}
|
||||
|
||||
gfx3DMatrix snappedTransform = SnapTransformTranslation(idealTransform, &residual);
|
||||
ToMatrix4x4(snappedTransform, mEffectiveTransform);
|
||||
mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual);
|
||||
// We always pass the ideal matrix down to our children, so there is no
|
||||
// need to apply any compensation using the residual from SnapTransformTranslation.
|
||||
ComputeEffectiveTransformsForChildren(idealTransform);
|
||||
|
||||
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
|
||||
|
||||
|
||||
Layer* child = GetFirstChild();
|
||||
bool hasSingleBlendingChild = false;
|
||||
if (!HasMultipleChildren() && child) {
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
ContainerLayer::RepositionChild(aChild, aAfter);
|
||||
}
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface);
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface);
|
||||
|
||||
/**
|
||||
* Returns true when:
|
||||
|
|
|
@ -599,7 +599,7 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
|
|||
// which depends on correct effective transforms
|
||||
mSnapEffectiveTransforms =
|
||||
mTarget ? !(mTarget->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING) : true;
|
||||
mRoot->ComputeEffectiveTransforms(mTarget ? gfx3DMatrix::From2D(mTarget->CurrentMatrix()) : gfx3DMatrix());
|
||||
mRoot->ComputeEffectiveTransforms(mTarget ? Matrix4x4::From2D(ToMatrix(mTarget->CurrentMatrix())) : Matrix4x4());
|
||||
|
||||
ToData(mRoot)->Validate(aCallback, aCallbackData);
|
||||
if (mRoot->GetMaskLayer()) {
|
||||
|
|
|
@ -74,13 +74,13 @@ public:
|
|||
}
|
||||
mValidRegion.SetEmpty();
|
||||
}
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
if (!BasicManager()->IsRetained()) {
|
||||
// Don't do any snapping of our transform, since we're just going to
|
||||
// draw straight through without intermediate buffers.
|
||||
gfx::ToMatrix4x4(GetLocalTransform() * aTransformToSurface, mEffectiveTransform);
|
||||
mEffectiveTransform = GetLocalTransform() * aTransformToSurface;
|
||||
if (gfxPoint(0,0) != mResidualTranslation) {
|
||||
mResidualTranslation = gfxPoint(0,0);
|
||||
mValidRegion.SetEmpty();
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
virtual Layer* AsLayer() { return this; }
|
||||
virtual ShadowableLayer* AsShadowableLayer() { return this; }
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
DefaultComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ public:
|
|||
|
||||
virtual void RenderLayer() { }
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
DefaultComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "ClientLayerManager.h"
|
||||
#include "CompositorChild.h" // for CompositorChild
|
||||
#include "GeckoProfiler.h" // for PROFILER_LABEL
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "gfxASurface.h" // for gfxASurface, etc
|
||||
#include "ipc/AutoOpenSurface.h" // for AutoOpenSurface
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
|
@ -183,7 +182,7 @@ ClientLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
|
|||
mThebesLayerCallback = aCallback;
|
||||
mThebesLayerCallbackData = aCallbackData;
|
||||
|
||||
GetRoot()->ComputeEffectiveTransforms(gfx3DMatrix());
|
||||
GetRoot()->ComputeEffectiveTransforms(Matrix4x4());
|
||||
|
||||
root->RenderLayer();
|
||||
|
||||
|
|
|
@ -214,7 +214,10 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
|||
* container->GetFrameMetrics().LayersPixelsPerCSSPixel()
|
||||
* LayerToScreenScale(1.0));
|
||||
}
|
||||
apzc->SetLayerHitTestData(visible, aTransform, aLayer->GetTransform());
|
||||
gfx3DMatrix transform;
|
||||
gfx::To3DMatrix(aLayer->GetTransform(), transform);
|
||||
|
||||
apzc->SetLayerHitTestData(visible, aTransform, transform);
|
||||
APZC_LOG("Setting rect(%f %f %f %f) as visible region for APZC %p\n", visible.x, visible.y,
|
||||
visible.width, visible.height,
|
||||
apzc);
|
||||
|
@ -260,7 +263,9 @@ APZCTreeManager::UpdatePanZoomControllerTree(CompositorParent* aCompositor,
|
|||
aTransform = gfx3DMatrix();
|
||||
} else {
|
||||
// Multiply child layer transforms on the left so they get applied first
|
||||
aTransform = aLayer->GetTransform() * aTransform;
|
||||
gfx3DMatrix matrix;
|
||||
gfx::To3DMatrix(aLayer->GetTransform(), matrix);
|
||||
aTransform = matrix * aTransform;
|
||||
}
|
||||
|
||||
uint64_t childLayersId = (aLayer->AsRefLayer() ? aLayer->AsRefLayer()->GetReferentId() : aLayersId);
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
struct nsCSSValueSharedList;
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
@ -122,7 +123,7 @@ AsyncCompositionManager::ComputeRotation()
|
|||
}
|
||||
|
||||
static bool
|
||||
GetBaseTransform2D(Layer* aLayer, gfxMatrix* aTransform)
|
||||
GetBaseTransform2D(Layer* aLayer, Matrix* aTransform)
|
||||
{
|
||||
// Start with the animated transform if there is one
|
||||
return (aLayer->AsLayerComposite()->GetShadowTransformSetByAnimation() ?
|
||||
|
@ -133,27 +134,28 @@ static void
|
|||
TranslateShadowLayer2D(Layer* aLayer,
|
||||
const gfxPoint& aTranslation)
|
||||
{
|
||||
gfxMatrix layerTransform;
|
||||
Matrix layerTransform;
|
||||
if (!GetBaseTransform2D(aLayer, &layerTransform)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply the 2D translation to the layer transform.
|
||||
layerTransform.x0 += aTranslation.x;
|
||||
layerTransform.y0 += aTranslation.y;
|
||||
layerTransform._31 += aTranslation.x;
|
||||
layerTransform._32 += aTranslation.y;
|
||||
|
||||
// The transform already takes the resolution scale into account. Since we
|
||||
// will apply the resolution scale again when computing the effective
|
||||
// transform, we must apply the inverse resolution scale here.
|
||||
gfx3DMatrix layerTransform3D = gfx3DMatrix::From2D(layerTransform);
|
||||
Matrix4x4 layerTransform3D = Matrix4x4::From2D(layerTransform);
|
||||
if (ContainerLayer* c = aLayer->AsContainerLayer()) {
|
||||
layerTransform3D.Scale(1.0f/c->GetPreXScale(),
|
||||
1.0f/c->GetPreYScale(),
|
||||
1);
|
||||
}
|
||||
layerTransform3D.ScalePost(1.0f/aLayer->GetPostXScale(),
|
||||
1.0f/aLayer->GetPostYScale(),
|
||||
1);
|
||||
layerTransform3D = layerTransform3D *
|
||||
Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
|
||||
1.0f/aLayer->GetPostYScale(),
|
||||
1);
|
||||
|
||||
LayerComposite* layerComposite = aLayer->AsLayerComposite();
|
||||
layerComposite->SetShadowTransform(layerTransform3D);
|
||||
|
@ -174,11 +176,11 @@ AccumulateLayerTransforms2D(Layer* aLayer,
|
|||
{
|
||||
// Accumulate the transforms between this layer and the subtree root layer.
|
||||
for (Layer* l = aLayer; l && l != aAncestor; l = l->GetParent()) {
|
||||
gfxMatrix l2D;
|
||||
Matrix l2D;
|
||||
if (!GetBaseTransform2D(l, &l2D)) {
|
||||
return false;
|
||||
}
|
||||
aMatrix.Multiply(l2D);
|
||||
aMatrix.Multiply(ThebesMatrix(l2D));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -251,7 +253,7 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
|||
}
|
||||
|
||||
gfxMatrix oldRootTransform;
|
||||
gfxMatrix newRootTransform;
|
||||
Matrix newRootTransform;
|
||||
if (!aPreviousTransformForRoot.Is2D(&oldRootTransform) ||
|
||||
!aTransformedSubtreeRoot->GetLocalTransform().Is2D(&newRootTransform)) {
|
||||
return;
|
||||
|
@ -260,7 +262,7 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
|||
// Calculate the cumulative transforms between the subtree root with the
|
||||
// old transform and the current transform.
|
||||
gfxMatrix oldCumulativeTransform = ancestorTransform * oldRootTransform;
|
||||
gfxMatrix newCumulativeTransform = ancestorTransform * newRootTransform;
|
||||
gfxMatrix newCumulativeTransform = ancestorTransform * ThebesMatrix(newRootTransform);
|
||||
if (newCumulativeTransform.IsSingular()) {
|
||||
return;
|
||||
}
|
||||
|
@ -269,7 +271,7 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
|||
|
||||
// Now work out the translation necessary to make sure the layer doesn't
|
||||
// move given the new sub-tree root transform.
|
||||
gfxMatrix layerTransform;
|
||||
Matrix layerTransform;
|
||||
if (!GetBaseTransform2D(aLayer, &layerTransform)) {
|
||||
return;
|
||||
}
|
||||
|
@ -286,10 +288,10 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
|||
|
||||
// Add the local layer transform to the two points to make the equation
|
||||
// below this section more convenient.
|
||||
gfxPoint anchor(anchorInOldSubtreeLayerSpace.x, anchorInOldSubtreeLayerSpace.y);
|
||||
gfxPoint offsetAnchor(offsetAnchorInOldSubtreeLayerSpace.x, offsetAnchorInOldSubtreeLayerSpace.y);
|
||||
gfxPoint locallyTransformedAnchor = layerTransform.Transform(anchor);
|
||||
gfxPoint locallyTransformedOffsetAnchor = layerTransform.Transform(offsetAnchor);
|
||||
Point anchor(anchorInOldSubtreeLayerSpace.x, anchorInOldSubtreeLayerSpace.y);
|
||||
Point offsetAnchor(offsetAnchorInOldSubtreeLayerSpace.x, offsetAnchorInOldSubtreeLayerSpace.y);
|
||||
Point locallyTransformedAnchor = layerTransform * anchor;
|
||||
Point locallyTransformedOffsetAnchor = layerTransform * offsetAnchor;
|
||||
|
||||
// Transforming the locallyTransformedAnchor by oldCumulativeTransform
|
||||
// returns the layer's anchor point relative to the parent of
|
||||
|
@ -300,8 +302,8 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
|||
// out the offset necessary to make sure the layer stays stationary.
|
||||
gfxPoint oldAnchorPositionInNewSpace =
|
||||
newCumulativeTransformInverse.Transform(
|
||||
oldCumulativeTransform.Transform(locallyTransformedOffsetAnchor));
|
||||
gfxPoint translation = oldAnchorPositionInNewSpace - locallyTransformedAnchor;
|
||||
oldCumulativeTransform.Transform(ThebesPoint(locallyTransformedOffsetAnchor)));
|
||||
gfxPoint translation = oldAnchorPositionInNewSpace - ThebesPoint(locallyTransformedAnchor);
|
||||
|
||||
if (aLayer->GetIsStickyPosition()) {
|
||||
// For sticky positioned layers, the difference between the two rectangles
|
||||
|
@ -332,7 +334,9 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
|||
if (aLayer->AsContainerLayer() &&
|
||||
aLayer->AsContainerLayer()->GetFrameMetrics().IsScrollable() &&
|
||||
aLayer != aTransformedSubtreeRoot) {
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, aLayer->GetTransform(), LayerMargin(0, 0, 0, 0));
|
||||
gfx3DMatrix matrix;
|
||||
To3DMatrix(aLayer->GetTransform(), matrix);
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, matrix, LayerMargin(0, 0, 0, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -389,7 +393,9 @@ SampleValue(float aPortion, Animation& aAnimation, nsStyleAnimation::Value& aSta
|
|||
transform.Translate(scaledOrigin);
|
||||
|
||||
InfallibleTArray<TransformFunction> functions;
|
||||
functions.AppendElement(TransformMatrix(transform));
|
||||
Matrix4x4 realTransform;
|
||||
ToMatrix4x4(transform, realTransform);
|
||||
functions.AppendElement(TransformMatrix(realTransform));
|
||||
*aValue = functions;
|
||||
}
|
||||
|
||||
|
@ -444,11 +450,11 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint)
|
|||
}
|
||||
case eCSSProperty_transform:
|
||||
{
|
||||
gfx3DMatrix matrix = interpolatedValue.get_ArrayOfTransformFunction()[0].get_TransformMatrix().value();
|
||||
Matrix4x4 matrix = interpolatedValue.get_ArrayOfTransformFunction()[0].get_TransformMatrix().value();
|
||||
if (ContainerLayer* c = aLayer->AsContainerLayer()) {
|
||||
matrix.ScalePost(c->GetInheritedXScale(),
|
||||
c->GetInheritedYScale(),
|
||||
1);
|
||||
matrix = matrix * Matrix4x4().Scale(c->GetInheritedXScale(),
|
||||
c->GetInheritedYScale(),
|
||||
1);
|
||||
}
|
||||
layerComposite->SetShadowTransform(matrix);
|
||||
layerComposite->SetShadowTransformSetByAnimation(true);
|
||||
|
@ -486,7 +492,8 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram
|
|||
|
||||
if (AsyncPanZoomController* controller = container->GetAsyncPanZoomController()) {
|
||||
LayerComposite* layerComposite = aLayer->AsLayerComposite();
|
||||
gfx3DMatrix oldTransform = aLayer->GetTransform();
|
||||
gfx3DMatrix oldTransform;
|
||||
To3DMatrix(aLayer->GetTransform(), oldTransform);
|
||||
|
||||
ViewTransform treeTransform;
|
||||
ScreenPoint scrollOffset;
|
||||
|
@ -511,16 +518,19 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram
|
|||
// Apply the render offset
|
||||
mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
|
||||
|
||||
gfx3DMatrix transform(gfx3DMatrix(treeTransform) * aLayer->GetTransform());
|
||||
Matrix4x4 transform;
|
||||
ToMatrix4x4(gfx3DMatrix(treeTransform), transform);
|
||||
transform = transform * aLayer->GetTransform();
|
||||
|
||||
// GetTransform already takes the pre- and post-scale into account. Since we
|
||||
// will apply the pre- and post-scale again when computing the effective
|
||||
// transform, we must apply the inverses here.
|
||||
transform.Scale(1.0f/container->GetPreXScale(),
|
||||
1.0f/container->GetPreYScale(),
|
||||
1);
|
||||
transform.ScalePost(1.0f/aLayer->GetPostXScale(),
|
||||
1.0f/aLayer->GetPostYScale(),
|
||||
1);
|
||||
transform = transform * Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
|
||||
1.0f/aLayer->GetPostYScale(),
|
||||
1);
|
||||
layerComposite->SetShadowTransform(transform);
|
||||
NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
|
||||
"overwriting animated transform!");
|
||||
|
@ -592,28 +602,28 @@ AsyncCompositionManager::ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer)
|
|||
gfx3DMatrix nontransientTransform = apzc->GetNontransientAsyncTransform();
|
||||
gfx3DMatrix transientTransform = asyncTransform * nontransientTransform.Inverse();
|
||||
|
||||
gfx3DMatrix scrollbarTransform;
|
||||
Matrix4x4 scrollbarTransform;
|
||||
if (aLayer->GetScrollbarDirection() == Layer::VERTICAL) {
|
||||
float scale = metrics.CalculateCompositedRectInCssPixels().height / metrics.mScrollableRect.height;
|
||||
scrollbarTransform.ScalePost(1.f, 1.f / transientTransform.GetYScale(), 1.f);
|
||||
scrollbarTransform.TranslatePost(gfxPoint3D(0, -transientTransform._42 * scale, 0));
|
||||
scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f, 1.f / transientTransform.GetYScale(), 1.f);
|
||||
scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(0, -transientTransform._42 * scale, 0);
|
||||
}
|
||||
if (aLayer->GetScrollbarDirection() == Layer::HORIZONTAL) {
|
||||
float scale = metrics.CalculateCompositedRectInCssPixels().width / metrics.mScrollableRect.width;
|
||||
scrollbarTransform.ScalePost(1.f / transientTransform.GetXScale(), 1.f, 1.f);
|
||||
scrollbarTransform.TranslatePost(gfxPoint3D(-transientTransform._41 * scale, 0, 0));
|
||||
scrollbarTransform = scrollbarTransform * Matrix4x4().Scale(1.f / transientTransform.GetXScale(), 1.f, 1.f);
|
||||
scrollbarTransform = scrollbarTransform * Matrix4x4().Translate(-transientTransform._41 * scale, 0, 0);
|
||||
}
|
||||
|
||||
gfx3DMatrix transform = scrollbarTransform * aLayer->GetTransform();
|
||||
Matrix4x4 transform = scrollbarTransform * aLayer->GetTransform();
|
||||
// GetTransform already takes the pre- and post-scale into account. Since we
|
||||
// will apply the pre- and post-scale again when computing the effective
|
||||
// transform, we must apply the inverses here.
|
||||
transform.Scale(1.0f/aLayer->GetPreXScale(),
|
||||
1.0f/aLayer->GetPreYScale(),
|
||||
1);
|
||||
transform.ScalePost(1.0f/aLayer->GetPostXScale(),
|
||||
1.0f/aLayer->GetPostYScale(),
|
||||
1);
|
||||
transform = transform * Matrix4x4().Scale(1.0f/aLayer->GetPostXScale(),
|
||||
1.0f/aLayer->GetPostYScale(),
|
||||
1);
|
||||
aLayer->AsLayerComposite()->SetShadowTransform(transform);
|
||||
|
||||
return;
|
||||
|
@ -629,7 +639,8 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
|
|||
const FrameMetrics& metrics = container->GetFrameMetrics();
|
||||
// We must apply the resolution scale before a pan/zoom transform, so we call
|
||||
// GetTransform here.
|
||||
const gfx3DMatrix& currentTransform = aLayer->GetTransform();
|
||||
gfx3DMatrix currentTransform;
|
||||
To3DMatrix(aLayer->GetTransform(), currentTransform);
|
||||
gfx3DMatrix oldTransform = currentTransform;
|
||||
|
||||
gfx3DMatrix treeTransform;
|
||||
|
@ -706,7 +717,9 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
|
|||
computedTransform.ScalePost(1.0f/container->GetPostXScale(),
|
||||
1.0f/container->GetPostYScale(),
|
||||
1);
|
||||
layerComposite->SetShadowTransform(computedTransform);
|
||||
Matrix4x4 matrix;
|
||||
ToMatrix4x4(computedTransform, matrix);
|
||||
layerComposite->SetShadowTransform(matrix);
|
||||
NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
|
||||
"overwriting animated transform!");
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE
|
||||
#include "mozilla/layers/LayerManagerComposite.h"
|
||||
|
||||
class gfx3DMatrix;
|
||||
struct nsIntPoint;
|
||||
struct nsIntRect;
|
||||
|
||||
|
@ -40,7 +39,7 @@ public:
|
|||
|
||||
virtual void RenderLayer(const nsIntRect& aClipRect) MOZ_OVERRIDE;
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) MOZ_OVERRIDE
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) MOZ_OVERRIDE
|
||||
{
|
||||
DefaultComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
@ -75,7 +74,7 @@ public:
|
|||
|
||||
virtual void RenderLayer(const nsIntRect& aClipRect) MOZ_OVERRIDE;
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) MOZ_OVERRIDE
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) MOZ_OVERRIDE
|
||||
{
|
||||
DefaultComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "CompositableHost.h" // for CompositableHost
|
||||
#include "Layers.h" // for WriteSnapshotToDumpFile, etc
|
||||
#include "gfx2DGlue.h" // for ToFilter, ToMatrix4x4
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "gfxRect.h" // for gfxRect
|
||||
#include "gfxUtils.h" // for gfxUtils, etc
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
|
@ -103,10 +102,10 @@ ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
|||
clipRect);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLayerComposite::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
void
|
||||
ImageLayerComposite::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
gfx3DMatrix local = GetLocalTransform();
|
||||
gfx::Matrix4x4 local = GetLocalTransform();
|
||||
|
||||
// Snap image edges to pixel boundaries
|
||||
gfxRect sourceRect(0, 0, 0, 0);
|
||||
|
@ -129,10 +128,9 @@ ImageLayerComposite::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToS
|
|||
// This makes our snapping equivalent to what would happen if our content
|
||||
// was drawn into a ThebesLayer (gfxContext would snap using the local
|
||||
// transform, then we'd snap again when compositing the ThebesLayer).
|
||||
gfx3DMatrix snappedTransform =
|
||||
mEffectiveTransform =
|
||||
SnapTransform(local, sourceRect, nullptr) *
|
||||
SnapTransformTranslation(aTransformToSurface, nullptr);
|
||||
gfx::ToMatrix4x4(snappedTransform, mEffectiveTransform);
|
||||
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "nsISupportsImpl.h" // for TextureImage::AddRef, etc
|
||||
#include "nscore.h" // for nsACString
|
||||
|
||||
class gfx3DMatrix;
|
||||
struct nsIntPoint;
|
||||
struct nsIntRect;
|
||||
|
||||
|
@ -46,7 +45,7 @@ public:
|
|||
|
||||
virtual void RenderLayer(const nsIntRect& aClipRect);
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) MOZ_OVERRIDE;
|
||||
virtual void ComputeEffectiveTransforms(const mozilla::gfx::Matrix4x4& aTransformToSurface) MOZ_OVERRIDE;
|
||||
|
||||
virtual void CleanupResources() MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback,
|
|||
|
||||
// The results of our drawing always go directly into a pixel buffer,
|
||||
// so we don't need to pass any global transform here.
|
||||
mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
|
||||
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
|
||||
|
||||
Render();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include <stdint.h> // for int32_t, uint32_t
|
||||
#include "GLDefs.h" // for GLenum
|
||||
#include "Layers.h"
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE
|
||||
#include "mozilla/RefPtr.h" // for RefPtr, TemporaryRef
|
||||
|
@ -344,7 +343,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void SetShadowTransform(const gfx3DMatrix& aMatrix)
|
||||
void SetShadowTransform(const gfx::Matrix4x4& aMatrix)
|
||||
{
|
||||
mShadowTransform = aMatrix;
|
||||
}
|
||||
|
@ -367,13 +366,13 @@ public:
|
|||
float GetShadowOpacity() { return mShadowOpacity; }
|
||||
const nsIntRect* GetShadowClipRect() { return mUseShadowClipRect ? &mShadowClipRect : nullptr; }
|
||||
const nsIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
|
||||
const gfx3DMatrix& GetShadowTransform() { return mShadowTransform; }
|
||||
const gfx::Matrix4x4& GetShadowTransform() { return mShadowTransform; }
|
||||
bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
|
||||
bool HasLayerBeenComposited() { return mLayerComposited; }
|
||||
bool GetClearFB() { return mClearFB; }
|
||||
|
||||
protected:
|
||||
gfx3DMatrix mShadowTransform;
|
||||
gfx::Matrix4x4 mShadowTransform;
|
||||
nsIntRegion mShadowVisibleRegion;
|
||||
nsIntRect mShadowClipRect;
|
||||
LayerManagerComposite* mCompositeManager;
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
|
||||
virtual void LayerManagerDestroyed();
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
DefaultComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
|
|
@ -383,7 +383,7 @@ LayerManagerD3D10::EndTransaction(DrawThebesLayerCallback aCallback,
|
|||
|
||||
// The results of our drawing always go directly into a pixel buffer,
|
||||
// so we don't need to pass any global transform here.
|
||||
mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
|
||||
mRoot->ComputeEffectiveTransforms(Matrix4x4());
|
||||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
MOZ_LAYERS_LOG((" ----- (beginning paint)"));
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
|
||||
virtual void LayerManagerDestroyed();
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
|
||||
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
|
||||
{
|
||||
DefaultComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ LayerManagerD3D9::EndTransaction(DrawThebesLayerCallback aCallback,
|
|||
|
||||
// The results of our drawing always go directly into a pixel buffer,
|
||||
// so we don't need to pass any global transform here.
|
||||
mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
|
||||
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
|
||||
|
||||
SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
|
||||
Render();
|
||||
|
|
|
@ -489,7 +489,7 @@ LayerTransactionParent::RecvGetTransform(PLayerParent* aParent,
|
|||
// from the shadow transform by undoing the translations in
|
||||
// AsyncCompositionManager::SampleValue.
|
||||
Layer* layer = cast(aParent)->AsLayer();
|
||||
*aTransform = layer->AsLayerComposite()->GetShadowTransform();
|
||||
gfx::To3DMatrix(layer->AsLayerComposite()->GetShadowTransform(), *aTransform);
|
||||
if (ContainerLayer* c = layer->AsContainerLayer()) {
|
||||
aTransform->ScalePost(1.0f/c->GetInheritedXScale(),
|
||||
1.0f/c->GetInheritedYScale(),
|
||||
|
|
|
@ -20,6 +20,7 @@ include "ImageLayers.h";
|
|||
using mozilla::GraphicsFilterType from "mozilla/GfxMessageUtils.h";
|
||||
using struct gfxRGBA from "gfxColor.h";
|
||||
using struct gfxPoint3D from "gfxPoint3D.h";
|
||||
using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
|
||||
using class gfx3DMatrix from "gfx3DMatrix.h";
|
||||
using nscoord from "nsCoord.h";
|
||||
using struct nsIntPoint from "nsPoint.h";
|
||||
|
@ -110,7 +111,7 @@ struct Scale {
|
|||
struct Skew { float x; float y; };
|
||||
struct SkewX { float x; };
|
||||
struct SkewY { float y; };
|
||||
struct TransformMatrix { gfx3DMatrix value; };
|
||||
struct TransformMatrix { Matrix4x4 value; };
|
||||
struct Translation {
|
||||
float x;
|
||||
float y;
|
||||
|
|
|
@ -61,7 +61,7 @@ class TestAPZCContainerLayer : public ContainerLayer {
|
|||
{}
|
||||
void RemoveChild(Layer* aChild) {}
|
||||
void InsertAfter(Layer* aChild, Layer* aAfter) {}
|
||||
void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) {}
|
||||
void ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) {}
|
||||
void RepositionChild(Layer* aChild, Layer* aAfter) {}
|
||||
};
|
||||
|
||||
|
@ -815,8 +815,8 @@ TEST(APZCTreeManager, HitTesting2) {
|
|||
gfx3DMatrix transformToGecko;
|
||||
|
||||
// Set a CSS transform on one of the layers.
|
||||
gfx3DMatrix transform;
|
||||
transform.ScalePost(2, 1, 1);
|
||||
Matrix4x4 transform;
|
||||
transform = transform * Matrix4x4().Scale(2, 1, 1);
|
||||
layers[2]->SetBaseTransform(transform);
|
||||
|
||||
// Make some other layers scrollable.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "gmock/gmock.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
class TestLayerManager: public LayerManager {
|
||||
|
@ -47,7 +48,7 @@ public:
|
|||
return TYPE_CONTAINER;
|
||||
}
|
||||
|
||||
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface) {
|
||||
virtual void ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface) {
|
||||
DefaultComputeEffectiveTransforms(aTransformToSurface);
|
||||
}
|
||||
|
||||
|
@ -124,7 +125,7 @@ TEST(Layers, Defaults) {
|
|||
TEST(Layers, Transform) {
|
||||
TestContainerLayer layer(nullptr);
|
||||
|
||||
gfx3DMatrix identity;
|
||||
Matrix4x4 identity;
|
||||
ASSERT_EQ(true, identity.IsIdentity());
|
||||
|
||||
ASSERT_EQ(identity, layer.GetTransform());
|
||||
|
@ -217,7 +218,9 @@ already_AddRefed<Layer> CreateLayerTree(
|
|||
} else {
|
||||
nsRefPtr<Layer> layer = CreateLayer(aLayerTreeDescription[i], manager.get());
|
||||
layer->SetVisibleRegion(aVisibleRegions[layerNumber]);
|
||||
layer->SetBaseTransform(aTransforms[layerNumber]);
|
||||
Matrix4x4 transform;
|
||||
ToMatrix4x4(aTransforms[layerNumber], transform);
|
||||
layer->SetBaseTransform(transform);
|
||||
aLayersOut.AppendElement(layer);
|
||||
layerNumber++;
|
||||
if (rootLayer && !parentContainerLayer) {
|
||||
|
@ -234,7 +237,7 @@ already_AddRefed<Layer> CreateLayerTree(
|
|||
}
|
||||
}
|
||||
if (rootLayer) {
|
||||
rootLayer->ComputeEffectiveTransforms(gfx3DMatrix());
|
||||
rootLayer->ComputeEffectiveTransforms(Matrix4x4());
|
||||
}
|
||||
return rootLayer.forget();
|
||||
}
|
||||
|
|
|
@ -676,6 +676,30 @@ gfxUtils::TransformRectToRect(const gfxRect& aFrom, const gfxPoint& aToTopLeft,
|
|||
return m;
|
||||
}
|
||||
|
||||
Matrix
|
||||
gfxUtils::TransformRectToRect(const gfxRect& aFrom, const IntPoint& aToTopLeft,
|
||||
const IntPoint& aToTopRight, const IntPoint& aToBottomRight)
|
||||
{
|
||||
Matrix m;
|
||||
if (aToTopRight.y == aToTopLeft.y && aToTopRight.x == aToBottomRight.x) {
|
||||
// Not a rotation, so xy and yx are zero
|
||||
m._12 = m._21 = 0.0;
|
||||
m._11 = (aToBottomRight.x - aToTopLeft.x)/aFrom.width;
|
||||
m._22 = (aToBottomRight.y - aToTopLeft.y)/aFrom.height;
|
||||
m._31 = aToTopLeft.x - m._11*aFrom.x;
|
||||
m._32 = aToTopLeft.y - m._22*aFrom.y;
|
||||
} else {
|
||||
NS_ASSERTION(aToTopRight.y == aToBottomRight.y && aToTopRight.x == aToTopLeft.x,
|
||||
"Destination rectangle not axis-aligned");
|
||||
m._11 = m._22 = 0.0;
|
||||
m._21 = (aToBottomRight.x - aToTopLeft.x)/aFrom.height;
|
||||
m._12 = (aToBottomRight.y - aToTopLeft.y)/aFrom.width;
|
||||
m._31 = aToTopLeft.x - m._21*aFrom.y;
|
||||
m._32 = aToTopLeft.y - m._12*aFrom.x;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxUtils::GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,8 @@ class PlanarYCbCrData;
|
|||
|
||||
class gfxUtils {
|
||||
public:
|
||||
typedef mozilla::gfx::IntPoint IntPoint;
|
||||
typedef mozilla::gfx::Matrix Matrix;
|
||||
/*
|
||||
* Premultiply or Unpremultiply aSourceSurface, writing the result
|
||||
* to aDestSurface or back into aSourceSurface if aDestSurface is null.
|
||||
|
@ -109,6 +111,11 @@ public:
|
|||
const gfxPoint& aToTopRight,
|
||||
const gfxPoint& aToBottomRight);
|
||||
|
||||
static Matrix TransformRectToRect(const gfxRect& aFrom,
|
||||
const IntPoint& aToTopLeft,
|
||||
const IntPoint& aToTopRight,
|
||||
const IntPoint& aToBottomRight);
|
||||
|
||||
/**
|
||||
* If aIn can be represented exactly using an nsIntRect (i.e.
|
||||
* integer-aligned edges and coordinates in the int32_t range) then we
|
||||
|
|
|
@ -46,6 +46,10 @@ typedef uint32_t uint32;
|
|||
#define ARCH_CPU_SPARC_FAMILY 1
|
||||
#define ARCH_CPU_SPARC 1
|
||||
#define ARCH_CPU_64_BITS 1
|
||||
#elif defined(__aarch64__)
|
||||
#define ARCH_CPU_AARCH64_FAMILY 1
|
||||
#define ARCH_CPU_AARCH64 1
|
||||
#define ARCH_CPU_64_BITS 1
|
||||
#else
|
||||
#warning Please add support for your architecture in chromium_types.h
|
||||
#endif
|
||||
|
|
|
@ -355,9 +355,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeToISO2022JP)
|
|||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsISO2022KRToUnicode)
|
||||
|
||||
// ucvcn
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsGB2312ToUnicodeV2)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeToGB2312V2)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsGBKToUnicode)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeToGBK)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHZToUnicode)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeToHZ)
|
||||
|
@ -839,9 +837,9 @@ static const mozilla::Module::CIDEntry kUConvCIDs[] = {
|
|||
{ &kNS_JOHABTOUNICODE_CID, false, nullptr, nsJohabToUnicodeConstructor },
|
||||
{ &kNS_UNICODETOJOHAB_CID, false, nullptr, nsUnicodeToJohabConstructor },
|
||||
{ &kNS_ISO2022KRTOUNICODE_CID, false, nullptr, nsISO2022KRToUnicodeConstructor },
|
||||
{ &kNS_GB2312TOUNICODE_CID, false, nullptr, nsGB2312ToUnicodeV2Constructor },
|
||||
{ &kNS_GB2312TOUNICODE_CID, false, nullptr, nsGB18030ToUnicodeConstructor },
|
||||
{ &kNS_UNICODETOGB2312_CID, false, nullptr, nsUnicodeToGB2312V2Constructor },
|
||||
{ &kNS_GBKTOUNICODE_CID, false, nullptr, nsGBKToUnicodeConstructor },
|
||||
{ &kNS_GBKTOUNICODE_CID, false, nullptr, nsGB18030ToUnicodeConstructor },
|
||||
{ &kNS_UNICODETOGBK_CID, false, nullptr, nsUnicodeToGBKConstructor },
|
||||
{ &kNS_HZTOUNICODE_CID, false, nullptr, nsHZToUnicodeConstructor },
|
||||
{ &kNS_UNICODETOHZ_CID, false, nullptr, nsUnicodeToHZConstructor },
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
[test_bug335816.html]
|
||||
[test_bug843434.html]
|
||||
[test_bug959058-1.html]
|
||||
[test_bug959058-2.html]
|
||||
[test_long_doc.html]
|
||||
[test_singlebyte_overconsumption.html]
|
||||
[test_unicode_noncharacterescapes.html]
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=959058
|
||||
-->
|
||||
<head>
|
||||
<meta charset="gbk">
|
||||
<title>Test for Bug 959058</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">
|
||||
|
||||
/** Test for Bug 959058 **/
|
||||
|
||||
is("”9¸2", "\uD83C\uDF54", "Should have gotten a hamburger.");
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=959058">Mozilla Bug 959058</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=959058
|
||||
-->
|
||||
<head>
|
||||
<meta charset="gbk">
|
||||
<title>Test for Bug 959058</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">
|
||||
|
||||
/** Test for Bug 959058 **/
|
||||
|
||||
is("€", "\u20AC", "Should have gotten euro.");
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=959058">Mozilla Bug 959058</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -274,7 +274,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports
|
|||
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
|
||||
%}
|
||||
|
||||
[uuid(74109b69-de2f-4296-9e08-2a233eafa8f9)]
|
||||
[noscript, uuid(3d5a6320-8764-11e3-baa7-0800200c9a66)]
|
||||
interface nsIXPConnect : nsISupports
|
||||
{
|
||||
%{ C++
|
||||
|
|
|
@ -81,7 +81,7 @@ def print_header_file(fd, conf):
|
|||
fd.write("NS_NewDOM%s(nsIDOMEvent** aInstance, " % e)
|
||||
fd.write("mozilla::dom::EventTarget* aOwner, ")
|
||||
fd.write("nsPresContext* aPresContext, mozilla::WidgetEvent* aEvent);\n")
|
||||
|
||||
|
||||
fd.write("\n#endif\n")
|
||||
|
||||
def print_classes_file(fd, conf):
|
||||
|
@ -441,7 +441,12 @@ def write_cpp(eventname, iface, fd, conf):
|
|||
fd.write(");\n");
|
||||
fd.write(" NS_ENSURE_SUCCESS(rv, rv);\n")
|
||||
for a in attributes:
|
||||
fd.write(" m%s = a%s;\n" % (firstCap(a.name), firstCap(a.name)))
|
||||
if a.realtype.nativeType("in").count("nsAString"):
|
||||
fd.write(" if (!m%s.Assign(a%s, fallible_t())) {\n" % (firstCap(a.name), firstCap(a.name)))
|
||||
fd.write(" return NS_ERROR_OUT_OF_MEMORY;\n")
|
||||
fd.write(" }\n")
|
||||
else:
|
||||
fd.write(" m%s = a%s;\n" % (firstCap(a.name), firstCap(a.name)))
|
||||
fd.write(" return NS_OK;\n")
|
||||
fd.write("}\n\n")
|
||||
|
||||
|
|
|
@ -1497,15 +1497,15 @@ ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aAnimatedGeometryRoot
|
|||
RoundToMatchResidual(scaledOffset.y, data->mAnimatedGeometryRootPosition.y));
|
||||
data->mTranslation = pixOffset;
|
||||
pixOffset += mParameters.mOffset;
|
||||
gfxMatrix matrix;
|
||||
matrix.Translate(gfxPoint(pixOffset.x, pixOffset.y));
|
||||
layer->SetBaseTransform(gfx3DMatrix::From2D(matrix));
|
||||
Matrix matrix;
|
||||
matrix.Translate(pixOffset.x, pixOffset.y);
|
||||
layer->SetBaseTransform(Matrix4x4::From2D(matrix));
|
||||
|
||||
// FIXME: Temporary workaround for bug 681192 and bug 724786.
|
||||
#ifndef MOZ_ANDROID_OMTC
|
||||
// Calculate exact position of the top-left of the active scrolled root.
|
||||
// This might not be 0,0 due to the snapping in ScaleToNearestPixels.
|
||||
gfxPoint animatedGeometryRootTopLeft = scaledOffset - matrix.GetTranslation() + mParameters.mOffset;
|
||||
gfxPoint animatedGeometryRootTopLeft = scaledOffset - ThebesPoint(matrix.GetTranslation()) + mParameters.mOffset;
|
||||
// If it has changed, then we need to invalidate the entire layer since the
|
||||
// pixels in the layer buffer have the content at a (subpixel) offset
|
||||
// from what we need.
|
||||
|
@ -1552,7 +1552,8 @@ static void
|
|||
SetVisibleRegionForLayer(Layer* aLayer, const nsIntRegion& aLayerVisibleRegion,
|
||||
const nsIntRect& aRestrictToRect)
|
||||
{
|
||||
gfx3DMatrix transform = aLayer->GetTransform();
|
||||
gfx3DMatrix transform;
|
||||
To3DMatrix(aLayer->GetTransform(), transform);
|
||||
|
||||
// if 'transform' is not invertible, then nothing will be displayed
|
||||
// for the layer, so it doesn't really matter what we do here
|
||||
|
@ -1714,11 +1715,13 @@ ContainerState::SetFixedPositionLayerData(Layer* aLayer,
|
|||
static gfx3DMatrix
|
||||
GetTransformToRoot(Layer* aLayer)
|
||||
{
|
||||
gfx3DMatrix transform = aLayer->GetTransform();
|
||||
Matrix4x4 transform = aLayer->GetTransform();
|
||||
for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
|
||||
transform = transform * l->GetTransform();
|
||||
}
|
||||
return transform;
|
||||
gfx3DMatrix result;
|
||||
To3DMatrix(transform, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1807,7 +1810,7 @@ ContainerState::PopThebesLayerData()
|
|||
layer->SetClipRect(nullptr);
|
||||
}
|
||||
|
||||
gfxMatrix transform;
|
||||
Matrix transform;
|
||||
if (!layer->GetTransform().Is2D(&transform)) {
|
||||
NS_ERROR("Only 2D transformations currently supported");
|
||||
}
|
||||
|
@ -2960,9 +2963,9 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
|
|||
// Don't clamp the scale factor when the new desired scale factor matches the old one
|
||||
// or it was previously unscaled.
|
||||
bool clamp = true;
|
||||
gfxMatrix oldFrameTransform2d;
|
||||
Matrix oldFrameTransform2d;
|
||||
if (aLayer->GetBaseTransform().Is2D(&oldFrameTransform2d)) {
|
||||
gfxSize oldScale = RoundToFloatPrecision(oldFrameTransform2d.ScaleFactors(true));
|
||||
gfxSize oldScale = RoundToFloatPrecision(ThebesMatrix(oldFrameTransform2d).ScaleFactors(true));
|
||||
if (oldScale == scale || oldScale == gfxSize(1.0, 1.0)) {
|
||||
clamp = false;
|
||||
}
|
||||
|
@ -2985,7 +2988,9 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
|
|||
}
|
||||
|
||||
// Store the inverse of our resolution-scale on the layer
|
||||
aLayer->SetBaseTransform(transform);
|
||||
Matrix4x4 baseTransform;
|
||||
ToMatrix4x4(transform, baseTransform);
|
||||
aLayer->SetBaseTransform(baseTransform);
|
||||
aLayer->SetPreScale(1.0f/float(scale.width),
|
||||
1.0f/float(scale.height));
|
||||
aLayer->SetInheritedScale(aIncomingScale.mXScale,
|
||||
|
@ -3830,8 +3835,8 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip,
|
|||
maskLayer->SetContainer(container);
|
||||
|
||||
maskTransform.Invert();
|
||||
gfx3DMatrix matrix = gfx3DMatrix::From2D(ThebesMatrix(maskTransform));
|
||||
matrix.Translate(gfxPoint3D(mParameters.mOffset.x, mParameters.mOffset.y, 0));
|
||||
Matrix4x4 matrix = Matrix4x4::From2D(maskTransform);
|
||||
matrix.Translate(mParameters.mOffset.x, mParameters.mOffset.y, 0);
|
||||
maskLayer->SetBaseTransform(matrix);
|
||||
|
||||
// save the details of the clip in user data
|
||||
|
|
|
@ -224,7 +224,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
|||
}
|
||||
case eCSSKeyword_matrix:
|
||||
{
|
||||
gfx3DMatrix matrix;
|
||||
gfx::Matrix4x4 matrix;
|
||||
matrix._11 = array->Item(1).GetFloatValue();
|
||||
matrix._12 = array->Item(2).GetFloatValue();
|
||||
matrix._13 = 0;
|
||||
|
@ -246,7 +246,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
|||
}
|
||||
case eCSSKeyword_matrix3d:
|
||||
{
|
||||
gfx3DMatrix matrix;
|
||||
gfx::Matrix4x4 matrix;
|
||||
matrix._11 = array->Item(1).GetFloatValue();
|
||||
matrix._12 = array->Item(2).GetFloatValue();
|
||||
matrix._13 = array->Item(3).GetFloatValue();
|
||||
|
@ -275,7 +275,9 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
|||
canStoreInRuleTree,
|
||||
aBounds,
|
||||
aAppUnitsPerPixel);
|
||||
aFunctions.AppendElement(TransformMatrix(matrix));
|
||||
gfx::Matrix4x4 transform;
|
||||
gfx::ToMatrix4x4(matrix, transform);
|
||||
aFunctions.AppendElement(TransformMatrix(transform));
|
||||
break;
|
||||
}
|
||||
case eCSSKeyword_perspective:
|
||||
|
@ -1967,11 +1969,12 @@ nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& a
|
|||
mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize();
|
||||
NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!");
|
||||
|
||||
gfxMatrix transform;
|
||||
transform.Translate(mDestRect.TopLeft() + aOffset);
|
||||
gfxPoint p = mDestRect.TopLeft() + aOffset;
|
||||
gfx::Matrix transform;
|
||||
transform.Translate(p.x, p.y);
|
||||
transform.Scale(mDestRect.width/imageSize.width,
|
||||
mDestRect.height/imageSize.height);
|
||||
aLayer->SetBaseTransform(gfx3DMatrix::From2D(transform));
|
||||
aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
||||
aLayer->SetVisibleRegion(nsIntRect(0, 0, imageSize.width, imageSize.height));
|
||||
}
|
||||
|
||||
|
|
|
@ -4834,7 +4834,8 @@ nsIFrame::TryUpdateTransformOnly()
|
|||
// the transform and will need to schedule an invalidating paint.
|
||||
return false;
|
||||
}
|
||||
gfxMatrix transform, previousTransform;
|
||||
gfxMatrix transform;
|
||||
gfx::Matrix previousTransform;
|
||||
// FIXME/bug 796690 and 796705: in general, changes to 3D
|
||||
// transforms, or transform changes to properties other than
|
||||
// translation, may lead us to choose a different rendering
|
||||
|
@ -4845,13 +4846,15 @@ nsIFrame::TryUpdateTransformOnly()
|
|||
static const gfx::Float kError = 0.0001f;
|
||||
if (!transform3d.Is2D(&transform) ||
|
||||
!layer->GetBaseTransform().Is2D(&previousTransform) ||
|
||||
!gfx::FuzzyEqual(transform.xx, previousTransform.xx, kError) ||
|
||||
!gfx::FuzzyEqual(transform.yy, previousTransform.yy, kError) ||
|
||||
!gfx::FuzzyEqual(transform.xy, previousTransform.xy, kError) ||
|
||||
!gfx::FuzzyEqual(transform.yx, previousTransform.yx, kError)) {
|
||||
!gfx::FuzzyEqual(transform.xx, previousTransform._11, kError) ||
|
||||
!gfx::FuzzyEqual(transform.yy, previousTransform._22, kError) ||
|
||||
!gfx::FuzzyEqual(transform.xy, previousTransform._21, kError) ||
|
||||
!gfx::FuzzyEqual(transform.yx, previousTransform._12, kError)) {
|
||||
return false;
|
||||
}
|
||||
layer->SetBaseTransformForNextTransaction(transform3d);
|
||||
gfx::Matrix4x4 matrix;
|
||||
gfx::ToMatrix4x4(transform3d, matrix);
|
||||
layer->SetBaseTransformForNextTransaction(matrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -266,10 +266,11 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
presContext->AppUnitsToGfxUnits(area.height));
|
||||
|
||||
// Transform the canvas into the right place
|
||||
gfxMatrix transform;
|
||||
transform.Translate(r.TopLeft() + aContainerParameters.mOffset);
|
||||
gfx::Matrix transform;
|
||||
gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
|
||||
transform.Translate(p.x, p.y);
|
||||
transform.Scale(r.Width()/canvasSize.width, r.Height()/canvasSize.height);
|
||||
layer->SetBaseTransform(gfx3DMatrix::From2D(transform));
|
||||
layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
||||
layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
|
||||
layer->SetVisibleRegion(nsIntRect(0, 0, canvasSize.width, canvasSize.height));
|
||||
|
||||
|
|
|
@ -1360,11 +1360,12 @@ nsDisplayImage::ConfigureLayer(ImageLayer *aLayer, const nsIntPoint& aOffset)
|
|||
|
||||
const gfxRect destRect = GetDestRect();
|
||||
|
||||
gfxMatrix transform;
|
||||
transform.Translate(destRect.TopLeft() + aOffset);
|
||||
gfx::Matrix transform;
|
||||
gfxPoint p = destRect.TopLeft() + aOffset;
|
||||
transform.Translate(p.x, p.y);
|
||||
transform.Scale(destRect.Width()/imageWidth,
|
||||
destRect.Height()/imageHeight);
|
||||
aLayer->SetBaseTransform(gfx3DMatrix::From2D(transform));
|
||||
aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
||||
aLayer->SetVisibleRegion(nsIntRect(0, 0, imageWidth, imageHeight));
|
||||
}
|
||||
|
||||
|
|
|
@ -1637,10 +1637,11 @@ nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
|
||||
// Set a transform on the layer to draw the plugin in the right place
|
||||
gfxMatrix transform;
|
||||
transform.Translate(r.TopLeft() + aContainerParameters.mOffset);
|
||||
Matrix transform;
|
||||
gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
|
||||
transform.Translate(p.x, p.y);
|
||||
|
||||
layer->SetBaseTransform(gfx3DMatrix::From2D(transform));
|
||||
layer->SetBaseTransform(Matrix4x4::From2D(transform));
|
||||
layer->SetVisibleRegion(ThebesIntRect(IntRect(IntPoint(0, 0), size)));
|
||||
return layer.forget();
|
||||
}
|
||||
|
|
|
@ -7382,8 +7382,9 @@ nsTextFrame::GetPrefWidthTightBounds(nsRenderingContext* aContext,
|
|||
ComputeTransformedLength(provider),
|
||||
gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS,
|
||||
aContext->ThebesContext(), &provider);
|
||||
*aX = metrics.mBoundingBox.x;
|
||||
*aXMost = metrics.mBoundingBox.XMost();
|
||||
// Round it like nsTextFrame::ComputeTightBounds() to ensure consistency.
|
||||
*aX = NSToCoordFloor(metrics.mBoundingBox.x);
|
||||
*aXMost = NSToCoordCeil(metrics.mBoundingBox.XMost());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -215,10 +215,11 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
|
||||
layer->SetContentFlags(Layer::CONTENT_OPAQUE);
|
||||
// Set a transform on the layer to draw the video in the right place
|
||||
gfxMatrix transform;
|
||||
transform.Translate(r.TopLeft() + aContainerParameters.mOffset);
|
||||
gfx::Matrix transform;
|
||||
gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
|
||||
transform.Translate(p.x, p.y);
|
||||
transform.Scale(r.Width()/frameSize.width, r.Height()/frameSize.height);
|
||||
layer->SetBaseTransform(gfx3DMatrix::From2D(transform));
|
||||
layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
||||
layer->SetVisibleRegion(nsIntRect(0, 0, frameSize.width, frameSize.height));
|
||||
nsRefPtr<Layer> result = layer.forget();
|
||||
return result.forget();
|
||||
|
|
|
@ -227,7 +227,9 @@ BuildListForLayer(Layer* aLayer,
|
|||
gfx3DMatrix applyTransform = ComputeShadowTreeTransform(
|
||||
aSubdocFrame, aRootFrameLoader, metrics, view->GetViewConfig(),
|
||||
1 / GetXScale(aTransform), 1 / GetYScale(aTransform));
|
||||
transform = applyTransform * aLayer->GetTransform() * aTransform;
|
||||
gfx3DMatrix layerTransform;
|
||||
To3DMatrix(aLayer->GetTransform(), layerTransform);
|
||||
transform = applyTransform * layerTransform * aTransform;
|
||||
|
||||
// As mentioned above, bounds calculation also depends on the scale
|
||||
// of this layer.
|
||||
|
@ -246,7 +248,9 @@ BuildListForLayer(Layer* aLayer,
|
|||
new (aBuilder) nsDisplayRemoteShadow(aBuilder, aSubdocFrame, bounds, scrollId));
|
||||
|
||||
} else {
|
||||
transform = aLayer->GetTransform() * aTransform;
|
||||
gfx3DMatrix layerTransform;
|
||||
To3DMatrix(aLayer->GetTransform(), layerTransform);
|
||||
transform = layerTransform * aTransform;
|
||||
}
|
||||
|
||||
for (Layer* child = aLayer->GetFirstChild(); child;
|
||||
|
@ -271,7 +275,8 @@ TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader,
|
|||
|
||||
const FrameMetrics* metrics = GetFrameMetrics(aLayer);
|
||||
|
||||
gfx3DMatrix shadowTransform = aLayer->GetTransform();
|
||||
gfx3DMatrix shadowTransform;
|
||||
To3DMatrix(aLayer->GetTransform(), shadowTransform);
|
||||
ViewTransform layerTransform = aTransform;
|
||||
|
||||
if (metrics && metrics->IsScrollable()) {
|
||||
|
@ -279,7 +284,8 @@ TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader,
|
|||
const nsContentView* view =
|
||||
aFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId);
|
||||
NS_ABORT_IF_FALSE(view, "Array of views should be consistent with layer tree");
|
||||
const gfx3DMatrix& currentTransform = aLayer->GetTransform();
|
||||
gfx3DMatrix currentTransform;
|
||||
To3DMatrix(aLayer->GetTransform(), currentTransform);
|
||||
|
||||
const ViewConfig& config = view->GetViewConfig();
|
||||
// With temporary scale we should compensate translation
|
||||
|
@ -331,7 +337,9 @@ TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader,
|
|||
1.0f/aLayer->GetPostYScale(),
|
||||
1);
|
||||
|
||||
shadow->SetShadowTransform(shadowTransform);
|
||||
gfx::Matrix4x4 realShadowTransform;
|
||||
ToMatrix4x4(shadowTransform, realShadowTransform);
|
||||
shadow->SetShadowTransform(realShadowTransform);
|
||||
for (Layer* child = aLayer->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
TransformShadowTree(aBuilder, aFrameLoader, aFrame, child, layerTransform,
|
||||
|
@ -375,7 +383,8 @@ BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews,
|
|||
return;
|
||||
const FrameMetrics metrics = container->GetFrameMetrics();
|
||||
const ViewID scrollId = metrics.mScrollId;
|
||||
const gfx3DMatrix transform = aLayer->GetTransform();
|
||||
gfx3DMatrix transform;
|
||||
To3DMatrix(aLayer->GetTransform(), transform);
|
||||
aXScale *= GetXScale(transform);
|
||||
aYScale *= GetYScale(transform);
|
||||
|
||||
|
@ -449,7 +458,7 @@ BuildBackgroundPatternFor(ContainerLayer* aContainer,
|
|||
nsIFrame* aFrame)
|
||||
{
|
||||
LayerComposite* shadowRoot = aShadowRoot->AsLayerComposite();
|
||||
gfxMatrix t;
|
||||
gfx::Matrix t;
|
||||
if (!shadowRoot->GetShadowTransform().Is2D(&t)) {
|
||||
return;
|
||||
}
|
||||
|
@ -459,7 +468,7 @@ BuildBackgroundPatternFor(ContainerLayer* aContainer,
|
|||
nsIntRect contentBounds = shadowRoot->GetShadowVisibleRegion().GetBounds();
|
||||
gfxRect contentVis(contentBounds.x, contentBounds.y,
|
||||
contentBounds.width, contentBounds.height);
|
||||
gfxRect localContentVis(t.Transform(contentVis));
|
||||
gfxRect localContentVis(gfx::ThebesMatrix(t).Transform(contentVis));
|
||||
// Round *in* here because this area is punched out of the background
|
||||
localContentVis.RoundIn();
|
||||
nsIntRect localIntContentVis(localContentVis.X(), localContentVis.Y(),
|
||||
|
@ -850,8 +859,8 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
// container, but our display item is LAYER_ACTIVE_FORCE which
|
||||
// forces all layers above to be active.
|
||||
MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint());
|
||||
gfx3DMatrix m =
|
||||
gfx3DMatrix::Translation(offset.x, offset.y, 0.0);
|
||||
gfx::Matrix4x4 m;
|
||||
m.Translate(offset.x, offset.y, 0.0);
|
||||
// Remote content can't be repainted by us, so we multiply down
|
||||
// the resolution that our container expects onto our container.
|
||||
m.Scale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0);
|
||||
|
|
|
@ -29,6 +29,17 @@ nestegg_tstamp_scale
|
|||
nestegg_has_cues
|
||||
nestegg_sniff
|
||||
#endif
|
||||
#ifdef MOZ_WEBM_ENCODER
|
||||
writeSimpleBlock
|
||||
writeHeader
|
||||
writeSegmentInformation
|
||||
writeVideoTrack
|
||||
writeAudioTrack
|
||||
Ebml_Serialize
|
||||
Ebml_SerializeUnsigned
|
||||
Ebml_StartSubElement
|
||||
Ebml_EndSubElement
|
||||
#endif
|
||||
#ifdef MOZ_VPX
|
||||
#ifndef MOZ_NATIVE_LIBVPX
|
||||
vpx_codec_control_
|
||||
|
|
|
@ -44,8 +44,8 @@ skip-if(B2G) == quotes-1.xhtml quotes-1-ref.xhtml
|
|||
!= stretchy-underbar-1.xhtml stretchy-underbar-1-ref.xhtml
|
||||
== table-width-1.xhtml table-width-1-ref.xhtml
|
||||
== table-width-2.html table-width-2-ref.html
|
||||
fails-if(OSX||/^Windows\x20NT\x206\.[^0]/.test(http.oscpu)||Android) == table-width-3.html table-width-3-ref.html
|
||||
fails-if((OSX&&(OSX<10.8))||/^Windows\x20NT\x206\.[^0]/.test(http.oscpu)||Android) == table-width-4.html table-width-4-ref.html
|
||||
== table-width-3.html table-width-3-ref.html
|
||||
== table-width-4.html table-width-4-ref.html
|
||||
== underbar-width-1.xhtml underbar-width-1-ref.xhtml
|
||||
== mathml-type-supported.xhtml mathml-type-supported-ref.xml
|
||||
== mtable-align-negative-rownumber.html mtable-align-negative-rownumber-ref.html
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
<style type="text/css">
|
||||
html { background-color: grey; }
|
||||
td { border: 1px solid white;
|
||||
padding: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
padding-right: 1px;
|
||||
padding-left: 1px;
|
||||
background-color: black;
|
||||
color: red; }
|
||||
</style>
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
<style type="text/css">
|
||||
html { background-color: grey; }
|
||||
td { border: 1px solid white;
|
||||
padding: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
padding-right: 1px;
|
||||
padding-left: 1px;
|
||||
background-color: black;
|
||||
color: black; }
|
||||
</style>
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
<style type="text/css">
|
||||
html { background-color: grey; }
|
||||
td { border: 1px solid white;
|
||||
padding: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
padding-right: 1px;
|
||||
padding-left: 1px;
|
||||
background-color: black;
|
||||
color: red; }
|
||||
mi, mtext { font-size: 3em; }
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
<style type="text/css">
|
||||
html { background-color: grey; }
|
||||
td { border: 1px solid white;
|
||||
padding: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
padding-right: 1px;
|
||||
padding-left: 1px;
|
||||
background-color: black;
|
||||
color: black; }
|
||||
mi, mtext { font-size: 3em; }
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
<style type="text/css">
|
||||
html { background-color: grey; }
|
||||
td { border: 1px solid white;
|
||||
padding: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
padding-right: 1px;
|
||||
padding-left: 1px;
|
||||
background-color: black;
|
||||
color: black; }
|
||||
</style>
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
<style type="text/css">
|
||||
html { background-color: grey; }
|
||||
td { border: 1px solid white;
|
||||
padding: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
padding-right: 1px;
|
||||
padding-left: 1px;
|
||||
background-color: black;
|
||||
color: black; }
|
||||
</style>
|
||||
|
|
|
@ -110,8 +110,8 @@ class RefTest(object):
|
|||
|
||||
oldcwd = os.getcwd()
|
||||
|
||||
def __init__(self, automation):
|
||||
self.automation = automation
|
||||
def __init__(self, automation=None):
|
||||
self.automation = automation or Automation()
|
||||
|
||||
def getFullPath(self, path):
|
||||
"Get an absolute path relative to self.oldcwd."
|
||||
|
|
|
@ -400,11 +400,12 @@ nsDisplayXULImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset)
|
|||
|
||||
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
|
||||
|
||||
gfxMatrix transform;
|
||||
transform.Translate(destRect.TopLeft() + aOffset);
|
||||
gfxPoint p = destRect.TopLeft() + aOffset;
|
||||
gfx::Matrix transform;
|
||||
transform.Translate(p.x, p.y);
|
||||
transform.Scale(destRect.Width()/imageWidth,
|
||||
destRect.Height()/imageHeight);
|
||||
aLayer->SetBaseTransform(gfx3DMatrix::From2D(transform));
|
||||
aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
||||
|
||||
aLayer->SetVisibleRegion(nsIntRect(0, 0, imageWidth, imageHeight));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
# This file is automatically generated from the git commit history
|
||||
# by tools/gen_authors.sh.
|
||||
|
||||
Aaron Watry <awatry@gmail.com>
|
||||
Abo Talib Mahfoodh <ab.mahfoodh@gmail.com>
|
||||
Adrian Grange <agrange@google.com>
|
||||
Ahmad Sharif <asharif@google.com>
|
||||
Alexander Voronov <avoronov@graphics.cs.msu.ru>
|
||||
Alex Converse <alex.converse@gmail.com>
|
||||
Alexis Ballier <aballier@gentoo.org>
|
||||
Alok Ahuja <waveletcoeff@gmail.com>
|
||||
Alpha Lam <hclam@google.com>
|
||||
A.Mahfoodh <ab.mahfoodh@gmail.com>
|
||||
Ami Fischman <fischman@chromium.org>
|
||||
Andoni Morales Alastruey <ylatuya@gmail.com>
|
||||
Andres Mejia <mcitadel@gmail.com>
|
||||
Aron Rosenberg <arosenberg@logitech.com>
|
||||
Attila Nagy <attilanagy@google.com>
|
||||
changjun.yang <changjun.yang@intel.com>
|
||||
chm <chm@rock-chips.com>
|
||||
Christian Duvivier <cduvivier@google.com>
|
||||
Daniel Kang <ddkang@google.com>
|
||||
Deb Mukherjee <debargha@google.com>
|
||||
Dmitry Kovalev <dkovalev@google.com>
|
||||
Dragan Mrdjan <dmrdjan@mips.com>
|
||||
Erik Niemeyer <erik.a.niemeyer@gmail.com>
|
||||
Fabio Pedretti <fabio.ped@libero.it>
|
||||
Frank Galligan <fgalligan@google.com>
|
||||
Fredrik Söderquist <fs@opera.com>
|
||||
Fritz Koenig <frkoenig@google.com>
|
||||
Gaute Strokkenes <gaute.strokkenes@broadcom.com>
|
||||
Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
Guillaume Martres <gmartres@google.com>
|
||||
Guillermo Ballester Valor <gbvalor@gmail.com>
|
||||
Hangyu Kuang <hkuang@google.com>
|
||||
Henrik Lundin <hlundin@google.com>
|
||||
Hui Su <huisu@google.com>
|
||||
Ivan Maltz <ivanmaltz@google.com>
|
||||
James Berry <jamesberry@google.com>
|
||||
James Zern <jzern@google.com>
|
||||
Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
Janne Salonen <jsalonen@google.com>
|
||||
Jeff Faust <jfaust@google.com>
|
||||
Jeff Muizelaar <jmuizelaar@mozilla.com>
|
||||
Jeff Petkau <jpet@chromium.org>
|
||||
Jim Bankoski <jimbankoski@google.com>
|
||||
Jingning Han <jingning@google.com>
|
||||
Johann Koenig <johannkoenig@google.com>
|
||||
John Koleszar <jkoleszar@google.com>
|
||||
Joshua Bleecher Snyder <josh@treelinelabs.com>
|
||||
Joshua Litt <joshualitt@google.com>
|
||||
Justin Clift <justin@salasaga.org>
|
||||
Justin Lebar <justin.lebar@gmail.com>
|
||||
KO Myung-Hun <komh@chollian.net>
|
||||
Lou Quillio <louquillio@google.com>
|
||||
Luca Barbato <lu_zero@gentoo.org>
|
||||
Makoto Kato <makoto.kt@gmail.com>
|
||||
Mans Rullgard <mans@mansr.com>
|
||||
Marco Paniconi <marpan@google.com>
|
||||
Mark Mentovai <mark@chromium.org>
|
||||
Martin Ettl <ettl.martin78@googlemail.com>
|
||||
Martin Storsjo <martin@martin.st>
|
||||
Matthew Heaney <matthewjheaney@chromium.org>
|
||||
Michael Kohler <michaelkohler@live.com>
|
||||
Mike Frysinger <vapier@chromium.org>
|
||||
Mike Hommey <mhommey@mozilla.com>
|
||||
Mikhal Shemer <mikhal@google.com>
|
||||
Morton Jonuschat <yabawock@gmail.com>
|
||||
Parag Salasakar <img.mips1@gmail.com>
|
||||
Pascal Massimino <pascal.massimino@gmail.com>
|
||||
Patrik Westin <patrik.westin@gmail.com>
|
||||
Paul Wilkins <paulwilkins@google.com>
|
||||
Pavol Rusnak <stick@gk2.sk>
|
||||
Paweł Hajdan <phajdan@google.com>
|
||||
Philip Jägenstedt <philipj@opera.com>
|
||||
Priit Laes <plaes@plaes.org>
|
||||
Rafael Ávila de Espíndola <rafael.espindola@gmail.com>
|
||||
Rafaël Carré <funman@videolan.org>
|
||||
Ralph Giles <giles@xiph.org>
|
||||
Rob Bradford <rob@linux.intel.com>
|
||||
Ronald S. Bultje <rbultje@google.com>
|
||||
Sami Pietilä <samipietila@google.com>
|
||||
Scott Graham <scottmg@chromium.org>
|
||||
Scott LaVarnway <slavarnway@google.com>
|
||||
Shimon Doodkin <helpmepro1@gmail.com>
|
||||
Stefan Holmer <holmer@google.com>
|
||||
Suman Sunkara <sunkaras@google.com>
|
||||
Taekhyun Kim <takim@nvidia.com>
|
||||
Takanori MATSUURA <t.matsuu@gmail.com>
|
||||
Tamar Levy <tamar.levy@intel.com>
|
||||
Tero Rintaluoma <teror@google.com>
|
||||
Thijs Vermeir <thijsvermeir@gmail.com>
|
||||
Timothy B. Terriberry <tterribe@xiph.org>
|
||||
Tom Finegan <tomfinegan@google.com>
|
||||
Vignesh Venkatasubramanian <vigneshv@google.com>
|
||||
Yaowu Xu <yaowu@google.com>
|
||||
Yunqing Wang <yunqingwang@google.com>
|
||||
Google Inc.
|
||||
The Mozilla Foundation
|
||||
The Xiph.Org Foundation
|
|
@ -0,0 +1,79 @@
|
|||
// #include <strmif.h>
|
||||
#include "EbmlBufferWriter.h"
|
||||
#include "EbmlWriter.h"
|
||||
// #include <cassert>
|
||||
// #include <limits>
|
||||
// #include <malloc.h> //_alloca
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, int buffer_size, unsigned long len)
|
||||
{
|
||||
/* buffer_size:
|
||||
* 1 - int8_t;
|
||||
* 2 - int16_t;
|
||||
* 3 - int32_t;
|
||||
* 4 - int64_t;
|
||||
*/
|
||||
long i;
|
||||
for(i = len-1; i >= 0; i--) {
|
||||
unsigned char x;
|
||||
if (buffer_size == 1) {
|
||||
x = (char)(*(const int8_t *)buffer_in >> (i * 8));
|
||||
} else if (buffer_size == 2) {
|
||||
x = (char)(*(const int16_t *)buffer_in >> (i * 8));
|
||||
} else if (buffer_size == 4) {
|
||||
x = (char)(*(const int32_t *)buffer_in >> (i * 8));
|
||||
} else if (buffer_size == 8) {
|
||||
x = (char)(*(const int64_t *)buffer_in >> (i * 8));
|
||||
}
|
||||
Ebml_Write(glob, &x, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
|
||||
unsigned char *src = glob->buf;
|
||||
src += glob->offset;
|
||||
memcpy(src, buffer_in, len);
|
||||
glob->offset += len;
|
||||
}
|
||||
|
||||
static void _Serialize(EbmlGlobal *glob, const unsigned char *p, const unsigned char *q) {
|
||||
while (q != p) {
|
||||
--q;
|
||||
|
||||
memcpy(&(glob->buf[glob->offset]), q, 1);
|
||||
glob->offset++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
|
||||
// assert(buf);
|
||||
|
||||
const unsigned char *const p = (const unsigned char *)(buffer_in);
|
||||
const unsigned char *const q = p + len;
|
||||
|
||||
_Serialize(glob, p, q);
|
||||
}
|
||||
*/
|
||||
|
||||
void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id) {
|
||||
unsigned long long unknownLen = 0x01FFFFFFFFFFFFFFLL;
|
||||
Ebml_WriteID(glob, class_id);
|
||||
ebmlLoc->offset = glob->offset;
|
||||
// todo this is always taking 8 bytes, this may need later optimization
|
||||
Ebml_Serialize(glob, (void *)&unknownLen,sizeof(unknownLen), 8); // this is a key that says lenght unknown
|
||||
}
|
||||
|
||||
void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) {
|
||||
unsigned long long size = glob->offset - ebmlLoc->offset - 8;
|
||||
unsigned long long curOffset = glob->offset;
|
||||
glob->offset = ebmlLoc->offset;
|
||||
size |= 0x0100000000000000LL;
|
||||
Ebml_Serialize(glob, &size,sizeof(size), 8);
|
||||
glob->offset = curOffset;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef EBMLBUFFERWRITER_HPP
|
||||
#define EBMLBUFFERWRITER_HPP
|
||||
|
||||
typedef struct {
|
||||
unsigned long long offset;
|
||||
} EbmlLoc;
|
||||
|
||||
typedef struct {
|
||||
unsigned char *buf;
|
||||
unsigned int length;
|
||||
unsigned int offset;
|
||||
} EbmlGlobal;
|
||||
|
||||
void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len);
|
||||
void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in,
|
||||
int buffer_size, unsigned long len);
|
||||
void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id);
|
||||
void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc);
|
||||
|
||||
#endif
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче