Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2014-01-27 15:25:34 -05:00
commit 1e27e7bc1b
135 changed files with 3668 additions and 438 deletions

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -1,4 +1,4 @@
{
"revision": "c5f8db7e1e71a9bfe0d29665d2b4cf3ae773094e",
"revision": "1150c11d1e6f0f78df3552dfca8c53d5ed5c173d",
"repo_path": "/integration/gaia-central"
}

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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

View File

@ -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']

View File

@ -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 ==================================

View File

@ -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));

View File

@ -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;
}
}

View File

@ -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"

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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>

View File

@ -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)
{}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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) {

View File

@ -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 */

View File

@ -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);

View File

@ -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());
}

View File

@ -67,7 +67,6 @@ html|input.num {
}
html|div.plainfield {
-moz-margin-start: 1px;
color: -moz-fieldtext;
white-space: pre;
}

View File

@ -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

View File

@ -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>
{

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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 {

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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; }

View File

@ -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);
}
/**

View File

@ -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))

View File

@ -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) {

View File

@ -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:

View File

@ -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()) {

View File

@ -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();

View File

@ -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);
}

View File

@ -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();

View File

@ -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);

View File

@ -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!");

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -30,7 +30,7 @@ public:
virtual void LayerManagerDestroyed();
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
{
DefaultComputeEffectiveTransforms(aTransformToSurface);
}

View File

@ -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)"));

View File

@ -32,7 +32,7 @@ public:
virtual void LayerManagerDestroyed();
virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
{
DefaultComputeEffectiveTransforms(aTransformToSurface);
}

View File

@ -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();

View File

@ -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(),

View File

@ -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;

View File

@ -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.

View File

@ -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();
}

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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 },

View File

@ -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]

View File

@ -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>

View File

@ -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>

View File

@ -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++

View File

@ -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")

View File

@ -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

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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));

View File

@ -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));
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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_

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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; }

View File

@ -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; }

View File

@ -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>

View File

@ -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>

View File

@ -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."

View File

@ -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));
}

100
media/libmkv/AUTHORS Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

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