diff --git a/include/views/SkTouchGesture.h b/include/views/SkTouchGesture.h new file mode 100644 index 0000000000..79d4e283df --- /dev/null +++ b/include/views/SkTouchGesture.h @@ -0,0 +1,72 @@ +#ifndef SkTouchGesture_DEFINED +#define SkTouchGesture_DEFINED + +#include "SkTDArray.h" +#include "SkMatrix.h" + +struct SkFlingState { + SkFlingState() : fActive(false) {} + + bool isActive() const { return fActive; } + void stop() { fActive = false; } + + void reset(float sx, float sy); + bool evaluateMatrix(SkMatrix* matrix); + +private: + SkPoint fDirection; + SkScalar fSpeed0; + double fTime0; + bool fActive; +}; + +class SkTouchGesture { +public: + SkTouchGesture(); + ~SkTouchGesture(); + + void touchBegin(void* owner, float x, float y); + void touchMoved(void* owner, float x, float y); + void touchEnd(void* owner); + void reset(); + + bool isActive() { return fFlinger.isActive(); } + void stop() { fFlinger.stop(); } + + const SkMatrix& localM(); + const SkMatrix& globalM() const { return fGlobalM; } + +private: + enum State { + kEmpty_State, + kTranslate_State, + kZoom_State, + }; + + struct Rec { + void* fOwner; + float fStartX, fStartY; + float fPrevX, fPrevY; + float fLastX, fLastY; + SkMSec fPrevT, fLastT; + }; + SkTDArray fTouches; + + State fState; + SkMatrix fLocalM, fGlobalM; + SkFlingState fFlinger; + SkMSec fLastUpT; + SkPoint fLastUpP; + + + void flushLocalM(); + int findRec(void* owner) const; + void appendNewRec(void* owner, float x, float y); + float computePinch(const Rec&, const Rec&); + float limitTotalZoom(float scale) const; + bool handleDblTap(float, float); +}; + +#endif + + diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index b94960dbe4..3a7a1a6330 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -11,6 +11,7 @@ #include "SampleCode.h" #include "GrContext.h" +#include "SkTouchGesture.h" //#define DEFAULT_TO_GPU @@ -224,6 +225,9 @@ protected: virtual bool onEvent(const SkEvent& evt); virtual bool onQuery(SkEvent* evt); + virtual bool onClick(Click* click); + virtual Click* onFindClickHandler(SkScalar x, SkScalar y); + #if 0 virtual bool handleChar(SkUnichar uni); virtual bool handleEvent(const SkEvent& evt); @@ -243,6 +247,8 @@ private: GrContext* fGrContext; SkPath fClipPath; + SkTouchGesture fGesture; + enum CanvasType { kRaster_CanvasType, kPicture_CanvasType, @@ -395,6 +401,20 @@ void SampleWindow::draw(SkCanvas* canvas) { gAnimTimePrev = gAnimTime; gAnimTime = SkTime::GetMSecs(); + // Apply any gesture matrix + if (true) { + const SkMatrix& localM = fGesture.localM(); + if (localM.getType() & SkMatrix::kScale_Mask) { + canvas->setExternalMatrix(&localM); + } + canvas->concat(localM); + canvas->concat(fGesture.globalM()); + + if (fGesture.isActive()) { + this->inval(NULL); + } + } + if (fNClip) { this->INHERITED::draw(canvas); SkBitmap orig = capture_bitmap(canvas); @@ -825,6 +845,49 @@ bool SampleWindow::onHandleKey(SkKey key) { return this->INHERITED::onHandleKey(key); } +/////////////////////////////////////////////////////////////////////////////// + +static const char gGestureClickType[] = "GestureClickType"; + +class GestureClick : public SkView::Click { +public: + GestureClick(SkView* target) : SkView::Click(target) { + this->setType(gGestureClickType); + } + + static bool IsGesture(Click* click) { + return click->isType(gGestureClickType); + } +}; + +SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) { + return new GestureClick(this); +} + +bool SampleWindow::onClick(Click* click) { + if (GestureClick::IsGesture(click)) { + float x = SkScalarToFloat(click->fCurr.fX); + float y = SkScalarToFloat(click->fCurr.fY); + switch (click->fState) { + case SkView::Click::kDown_State: + fGesture.touchBegin(click, x, y); + break; + case SkView::Click::kMoved_State: + fGesture.touchMoved(click, x, y); + this->inval(NULL); + break; + case SkView::Click::kUp_State: + fGesture.touchEnd(click); + this->inval(NULL); + break; + } + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + void SampleWindow::loadView(SkView* view) { SkView::F2BIter iter(this); SkView* prev = iter.next(); diff --git a/src/views/SkTouchGesture.cpp b/src/views/SkTouchGesture.cpp new file mode 100644 index 0000000000..70eb6d3c9d --- /dev/null +++ b/src/views/SkTouchGesture.cpp @@ -0,0 +1,336 @@ +/* + Copyright 2010 Google Inc. + + 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. + */ + + +#include "SkTouchGesture.h" +#include "SkMatrix.h" +#include "SkTime.h" + +#define DISCRETIZE_TRANSLATE_TO_AVOID_FLICKER true + +static const float MAX_FLING_SPEED = 1500; + +static float pin_max_fling(float speed) { + if (speed > MAX_FLING_SPEED) { + speed = MAX_FLING_SPEED; + } + return speed; +} + +static double getseconds() { + return SkTime::GetMSecs() * 0.001; +} + +// returns +1 or -1, depending on the sign of x +// returns +1 if x is zero +static SkScalar SkScalarSign(SkScalar x) { + SkScalar sign = SK_Scalar1; + if (x < 0) { + sign = -sign; + } + return sign; +} + +static void unit_axis_align(SkVector* unit) { + const SkScalar TOLERANCE = SkDoubleToScalar(0.15); + if (SkScalarAbs(unit->fX) < TOLERANCE) { + unit->fX = 0; + unit->fY = SkScalarSign(unit->fY); + } else if (SkScalarAbs(unit->fY) < TOLERANCE) { + unit->fX = SkScalarSign(unit->fX); + unit->fY = 0; + } +} + +void SkFlingState::reset(float sx, float sy) { + fActive = true; + fDirection.set(sx, sy); + fSpeed0 = SkPoint::Normalize(&fDirection); + fSpeed0 = pin_max_fling(fSpeed0); + fTime0 = getseconds(); + + unit_axis_align(&fDirection); +// printf("---- speed %g dir %g %g\n", fSpeed0, fDirection.fX, fDirection.fY); +} + +bool SkFlingState::evaluateMatrix(SkMatrix* matrix) { + if (!fActive) { + return false; + } + + const float t = getseconds() - fTime0; + const float MIN_SPEED = 2; + const float K0 = 5.0; + const float K1 = 0.02; + const float speed = fSpeed0 * (sk_float_exp(- K0 * t) - K1); + if (speed <= MIN_SPEED) { + fActive = false; + return false; + } + float dist = (fSpeed0 - speed) / K0; + +// printf("---- time %g speed %g dist %g\n", t, speed, dist); + float tx = fDirection.fX * dist; + float ty = fDirection.fY * dist; + if (DISCRETIZE_TRANSLATE_TO_AVOID_FLICKER) { + tx = sk_float_round2int(tx); + ty = sk_float_round2int(ty); + } + matrix->setTranslate(tx, ty); +// printf("---- evaluate (%g %g)\n", tx, ty); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +static const SkMSec MAX_DBL_TAP_INTERVAL = 300; +static const float MAX_DBL_TAP_DISTANCE = 100; +static const float MAX_JITTER_RADIUS = 2; + +// if true, then ignore the touch-move, 'cause its probably just jitter +static bool close_enough_for_jitter(float x0, float y0, float x1, float y1) { + return sk_float_abs(x0 - x1) <= MAX_JITTER_RADIUS && + sk_float_abs(y0 - y1) <= MAX_JITTER_RADIUS; +} + +/////////////////////////////////////////////////////////////////////////////// + +SkTouchGesture::SkTouchGesture() { + this->reset(); +} + +SkTouchGesture::~SkTouchGesture() { +} + +void SkTouchGesture::reset() { + fTouches.reset(); + fState = kEmpty_State; + fLocalM.reset(); + fGlobalM.reset(); + + fLastUpT = SkTime::GetMSecs() - 2*MAX_DBL_TAP_INTERVAL; + fLastUpP.set(0, 0); +} + +void SkTouchGesture::flushLocalM() { + fGlobalM.postConcat(fLocalM); + fLocalM.reset(); +} + +const SkMatrix& SkTouchGesture::localM() { + if (fFlinger.isActive()) { + if (!fFlinger.evaluateMatrix(&fLocalM)) { + this->flushLocalM(); + } + } + return fLocalM; +} + +void SkTouchGesture::appendNewRec(void* owner, float x, float y) { + Rec* rec = fTouches.append(); + rec->fOwner = owner; + rec->fStartX = rec->fPrevX = rec->fLastX = x; + rec->fStartY = rec->fPrevY = rec->fLastY = y; + rec->fLastT = rec->fPrevT = SkTime::GetMSecs(); +} + +void SkTouchGesture::touchBegin(void* owner, float x, float y) { +// GrPrintf("--- %d touchBegin %p %g %g\n", fTouches.count(), owner, x, y); + + int index = this->findRec(owner); + if (index >= 0) { + this->flushLocalM(); + fTouches.removeShuffle(index); + SkDebugf("---- already exists, removing\n"); + } + + if (fTouches.count() == 2) { + return; + } + + this->flushLocalM(); + fFlinger.stop(); + + this->appendNewRec(owner, x, y); + + switch (fTouches.count()) { + case 1: + fState = kTranslate_State; + break; + case 2: + fState = kZoom_State; + break; + default: + break; + } +} + +int SkTouchGesture::findRec(void* owner) const { + for (int i = 0; i < fTouches.count(); i++) { + if (owner == fTouches[i].fOwner) { + return i; + } + } + return -1; +} + +static float center(float pos0, float pos1) { + return (pos0 + pos1) * 0.5f; +} + +static const float MAX_ZOOM_SCALE = 4; +static const float MIN_ZOOM_SCALE = 0.25f; + +float SkTouchGesture::limitTotalZoom(float scale) const { + // this query works 'cause we know that we're square-scale w/ no skew/rotation + const float curr = fGlobalM[0]; + + if (scale > 1 && curr * scale > MAX_ZOOM_SCALE) { + scale = MAX_ZOOM_SCALE / curr; + } else if (scale < 1 && curr * scale < MIN_ZOOM_SCALE) { + scale = MIN_ZOOM_SCALE / curr; + } + return scale; +} + +void SkTouchGesture::touchMoved(void* owner, float x, float y) { +// GrPrintf("--- %d touchMoved %p %g %g\n", fTouches.count(), owner, x, y); + + SkASSERT(kEmpty_State != fState); + + int index = this->findRec(owner); + if (index < 0) { + // not found, so I guess we should add it... + SkDebugf("---- add missing begin\n"); + this->appendNewRec(owner, x, y); + index = fTouches.count() - 1; + } + + Rec& rec = fTouches[index]; + + // not sure how valuable this is + if (fTouches.count() == 2) { + if (close_enough_for_jitter(rec.fLastX, rec.fLastY, x, y)) { +// GrPrintf("--- drop touchMove, withing jitter tolerance %g %g\n", rec.fLastX - x, rec.fLastY - y); + return; + } + } + + rec.fPrevX = rec.fLastX; rec.fLastX = x; + rec.fPrevY = rec.fLastY; rec.fLastY = y; + rec.fPrevT = rec.fLastT; rec.fLastT = SkTime::GetMSecs(); + + switch (fTouches.count()) { + case 1: { + float dx = rec.fLastX - rec.fStartX; + float dy = rec.fLastY - rec.fStartY; + dx = (float)sk_float_round2int(dx); + dy = (float)sk_float_round2int(dy); + fLocalM.setTranslate(dx, dy); + } break; + case 2: { + SkASSERT(kZoom_State == fState); + const Rec& rec0 = fTouches[0]; + const Rec& rec1 = fTouches[1]; + + float scale = this->computePinch(rec0, rec1); + scale = this->limitTotalZoom(scale); + + fLocalM.setTranslate(-center(rec0.fStartX, rec1.fStartX), + -center(rec0.fStartY, rec1.fStartY)); + fLocalM.postScale(scale, scale); + fLocalM.postTranslate(center(rec0.fLastX, rec1.fLastX), + center(rec0.fLastY, rec1.fLastY)); + } break; + default: + break; + } +} + +void SkTouchGesture::touchEnd(void* owner) { +// GrPrintf("--- %d touchEnd %p\n", fTouches.count(), owner); + + int index = this->findRec(owner); + if (index < 0) { + SkDebugf("--- not found\n"); + return; + } + + const Rec& rec = fTouches[index]; + if (this->handleDblTap(rec.fLastX, rec.fLastY)) { + return; + } + + // count() reflects the number before we removed the owner + switch (fTouches.count()) { + case 1: { + this->flushLocalM(); + float dx = rec.fLastX - rec.fPrevX; + float dy = rec.fLastY - rec.fPrevY; + float dur = (rec.fLastT - rec.fPrevT) * 0.001f; + if (dur > 0) { + fFlinger.reset(dx / dur, dy / dur); + } + fState = kEmpty_State; + } break; + case 2: + this->flushLocalM(); + SkASSERT(kZoom_State == fState); + fState = kEmpty_State; + break; + default: + SkASSERT(kZoom_State == fState); + break; + } + + fTouches.removeShuffle(index); +} + +float SkTouchGesture::computePinch(const Rec& rec0, const Rec& rec1) { + double dx = rec0.fStartX - rec1.fStartX; + double dy = rec0.fStartY - rec1.fStartY; + double dist0 = sqrt(dx*dx + dy*dy); + + dx = rec0.fLastX - rec1.fLastX; + dy = rec0.fLastY - rec1.fLastY; + double dist1 = sqrt(dx*dx + dy*dy); + + double scale = dist1 / dist0; + return (float)scale; +} + +bool SkTouchGesture::handleDblTap(float x, float y) { + bool found = false; + SkMSec now = SkTime::GetMSecs(); + if (now - fLastUpT <= MAX_DBL_TAP_INTERVAL) { + if (SkPoint::Length(fLastUpP.fX - x, + fLastUpP.fY - y) <= MAX_DBL_TAP_DISTANCE) { + fFlinger.stop(); + fLocalM.reset(); + fGlobalM.reset(); + fTouches.reset(); + fState = kEmpty_State; + found = true; + } + } + + fLastUpT = now; + fLastUpP.set(x, y); + return found; +} + + diff --git a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj index 9baf85c0c4..240e8b583b 100644 --- a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj +++ b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj @@ -77,12 +77,15 @@ 009F9C0E12C39A9C00C7FD4A /* SkGrTexturePixelRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 009F9C0812C39A9C00C7FD4A /* SkGrTexturePixelRef.cpp */; }; 009F9D0612C3E89F00C7FD4A /* SampleTiling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7CAF0F01658C00A2D6EE /* SampleTiling.cpp */; }; 009F9D0A12C3E8AF00C7FD4A /* SampleFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE280F00A12400695E8C /* SampleFilter.cpp */; }; - 009F9D1A12C3EB2600C7FD4A /* SampleGM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27C4625412BFB2F300DBB1F6 /* SampleGM.cpp */; }; 00A728270FD43D0400D5051F /* SampleMovie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F6760FCCCB01002BD8B4 /* SampleMovie.cpp */; }; 00A7282F0FD43D3700D5051F /* SkMovie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A7282D0FD43D3700D5051F /* SkMovie.cpp */; }; 00AF787E0FE94433007F9650 /* SamplePath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00003C640EFC22A8000FF73A /* SamplePath.cpp */; }; 00AF9B18103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */; }; + 00B59889132FB8D10087BF25 /* SampleXfermodes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7CB20F01658C00A2D6EE /* SampleXfermodes.cpp */; }; + 00B5993D1330DBCB0087BF25 /* SkTouchGesture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00B5993C1330DBCB0087BF25 /* SkTouchGesture.cpp */; }; 00BB289B104781D00057BF7E /* SampleForth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00BB289A104781D00057BF7E /* SampleForth.cpp */; }; + 00C3AA60132F8D3D00C22CE7 /* SampleComplexClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5558AEE131EBA1E00C71009 /* SampleComplexClip.cpp */; }; + 00C3AA75132F8D5E00C22CE7 /* SampleGM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27C4625412BFB2F300DBB1F6 /* SampleGM.cpp */; }; 00EB4593104DBB18002B413E /* ForthTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00EB4592104DBB18002B413E /* ForthTests.cpp */; }; 00ED55F3104A10EB00F51FF8 /* StdWords.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00ED55F2104A10EB00F51FF8 /* StdWords.cpp */; }; 00F0441010B447160049C54C /* SamplePathClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007C785D0F3B4C230004B142 /* SamplePathClip.cpp */; }; @@ -146,13 +149,11 @@ 8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */; }; 8D0C4E8E0486CD37000505A6 /* main.nib in Resources */ = {isa = PBXBuildFile; fileRef = 02345980000FD03B11CA0E72 /* main.nib */; }; 8D0C4E920486CD37000505A6 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20286C33FDCF999611CA2CEA /* Carbon.framework */; }; - D5558AEF131EBA1E00C71009 /* SampleComplexClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5558AEE131EBA1E00C71009 /* SampleComplexClip.cpp */; }; D5558B29131EBC9C00C71009 /* SampleFillType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE270F00A12400695E8C /* SampleFillType.cpp */; }; D55BEE6712EF44B90055D6FD /* shadertext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D55BEE6612EF44B90055D6FD /* shadertext.cpp */; }; D5962B3A12EDFC7600B478DF /* SampleShaderText.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5962B3812EDFC7600B478DF /* SampleShaderText.cpp */; }; D5A682D712E9CE8500CDDDC6 /* SamplePatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE340F00A12400695E8C /* SamplePatch.cpp */; }; D5BF1C5A131D449500C4B94B /* SampleAll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F6740FCCCB01002BD8B4 /* SampleAll.cpp */; }; - D5BF1CFD131D500A00C4B94B /* SampleXfermodes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007A7CB20F01658C00A2D6EE /* SampleXfermodes.cpp */; }; D5F700EA1326C6C8002FC60D /* SkPDFShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5F700E81326C6C8002FC60D /* SkPDFShader.cpp */; }; D5F700EB1326C6C8002FC60D /* SkPDFUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5F700E91326C6C8002FC60D /* SkPDFUtils.cpp */; }; /* End PBXBuildFile section */ @@ -319,6 +320,7 @@ 00A7282D0FD43D3700D5051F /* SkMovie.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkMovie.cpp; path = ../../src/images/SkMovie.cpp; sourceTree = SOURCE_ROOT; }; 00A7282E0FD43D3700D5051F /* SkMovie_gif.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkMovie_gif.cpp; path = ../../src/images/SkMovie_gif.cpp; sourceTree = SOURCE_ROOT; }; 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleDitherBitmap.cpp; path = ../../samplecode/SampleDitherBitmap.cpp; sourceTree = SOURCE_ROOT; }; + 00B5993C1330DBCB0087BF25 /* SkTouchGesture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkTouchGesture.cpp; path = ../../src/views/SkTouchGesture.cpp; sourceTree = SOURCE_ROOT; }; 00BB289A104781D00057BF7E /* SampleForth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleForth.cpp; path = ../../forth/SampleForth.cpp; sourceTree = SOURCE_ROOT; }; 00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleGradients.cpp; path = ../../samplecode/SampleGradients.cpp; sourceTree = SOURCE_ROOT; }; 00D6B5CB0F72DC4300C466B9 /* SampleFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFuzz.cpp; path = ../../samplecode/SampleFuzz.cpp; sourceTree = SOURCE_ROOT; }; @@ -521,6 +523,7 @@ 00003C6A0EFC22AD000FF73A /* views */ = { isa = PBXGroup; children = ( + 00B5993C1330DBCB0087BF25 /* SkTouchGesture.cpp */, 00281C661083CF5100BCCB06 /* SkTextBox.cpp */, 00003CA30EFC235F000FF73A /* SkXMLParser_empty.cpp */, 00003C9A0EFC233F000FF73A /* SkDOM.cpp */, @@ -1032,16 +1035,17 @@ 009F9C0E12C39A9C00C7FD4A /* SkGrTexturePixelRef.cpp in Sources */, 009F9D0612C3E89F00C7FD4A /* SampleTiling.cpp in Sources */, 009F9D0A12C3E8AF00C7FD4A /* SampleFilter.cpp in Sources */, - 009F9D1A12C3EB2600C7FD4A /* SampleGM.cpp in Sources */, D5A682D712E9CE8500CDDDC6 /* SamplePatch.cpp in Sources */, D5962B3A12EDFC7600B478DF /* SampleShaderText.cpp in Sources */, D55BEE6712EF44B90055D6FD /* shadertext.cpp in Sources */, D5BF1C5A131D449500C4B94B /* SampleAll.cpp in Sources */, - D5BF1CFD131D500A00C4B94B /* SampleXfermodes.cpp in Sources */, - D5558AEF131EBA1E00C71009 /* SampleComplexClip.cpp in Sources */, D5558B29131EBC9C00C71009 /* SampleFillType.cpp in Sources */, D5F700EA1326C6C8002FC60D /* SkPDFShader.cpp in Sources */, D5F700EB1326C6C8002FC60D /* SkPDFUtils.cpp in Sources */, + 00C3AA60132F8D3D00C22CE7 /* SampleComplexClip.cpp in Sources */, + 00C3AA75132F8D5E00C22CE7 /* SampleGM.cpp in Sources */, + 00B59889132FB8D10087BF25 /* SampleXfermodes.cpp in Sources */, + 00B5993D1330DBCB0087BF25 /* SkTouchGesture.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1157,7 +1161,11 @@ /usr/lib, /opt/local/lib, ); - OTHER_LDFLAGS = "-lexpat"; + OTHER_LDFLAGS = ( + "-L/usr/X11/lib", + "-lexpat", + "-lfreetype", + ); PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; SDKROOT = ""; USER_HEADER_SEARCH_PATHS = "../../gpu/include ../../src/core ../../include/** ../../gm"; @@ -1183,7 +1191,11 @@ /usr/lib, /opt/local/lib, ); - OTHER_LDFLAGS = "-lexpat"; + OTHER_LDFLAGS = ( + "-L/usr/X11/lib", + "-lexpat", + "-lfreetype", + ); SDKROOT = ""; USER_HEADER_SEARCH_PATHS = "../../gpu/include ../../src/core ../../include/** ../../gm"; };